folder restructure for hunting queries, exploration queries, and built-in alerts aka detections. (#12)

This commit is contained in:
timbMSFT 2019-01-24 10:30:15 +00:00 коммит произвёл GitHub
Родитель d104b28411
Коммит 38faeb1656
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
30 изменённых файлов: 557 добавлений и 438 удалений

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

@ -1,14 +1,31 @@
// Finding base64 encoded PE files header seen in the command line parameters
// Tags: #Initial Access, #Execution, #Defense Evasion
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
FolderPath = "",
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
processEvents};
ProcessCreationEvents
| where ProcessCommandLine contains "TVqQAAMAAAAEAAA"
// Name: Base64 encoded Windows executables in process commandlines
// Description: finds instances of base64 encoded PE files header seen in process command line parameter.
// Severity: Medium
// QueryFrequency: 24
// QueryPeriod: 24
// AlertTriggerOperator: gt
// AlertTriggerThreshold: 0
// Data source: SecurityEvent
// Techniques: #Initial Access, #Execution, #Defense Evasion
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
FolderPath = "",
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
processEvents};
ProcessCreationEvents
| where ProcessCommandLine contains "TVqQAAMAAAAEAAA"
| where TimeGenerated >= ago(24h)
| top 1000 by TimeGenerated

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

@ -0,0 +1,40 @@
// Name: Process executed from binary hidden in Base64 encoded file.
// Description: Encoding malicious software is a technique to obfuscate files from detection.
// The first ProcessCommandLine component is looking for Python decoding base64
// The second ProcesssCommandLine component is looking for the Bash/sh commandline base64 decoding tool
// The third one is looking for Ruby decoding base64
// Severity: Medium
// QueryFrequency: 24
// QueryPeriod: 24
// AlertTriggerOperator: gt
// AlertTriggerThreshold: 0
// Data source: SecurityEvent
// Techniques: #Initial Access, #Execution, #Defense Evasion
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName,AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1], // convert SecurityEvents raw schema to get FileName & CommandLine
ProcessCommandLine = CommandLine,
FolderPath = "",
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
processEvents ;
};
ProcessCreationEvents
| where TimeGenerated > ago(1d)
| where ProcessCommandLine contains ".decode('base64')"
or ProcessCommandLine contains "base64 --decode"
or ProcessCommandLine contains ".decode64("
| project TimeGenerated , ComputerName , FileName , ProcessCommandLine , InitiatingProcessCommandLine
| top 100 by EventTime

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

@ -1,15 +1,31 @@
// Finding attackers hiding malware in the recycle bin.
// Read more here: https://azure.microsoft.com/en-us/blog/how-azure-security-center-helps-reveal-a-cyberattack/
// Tags: #Execution, #Defense Evasion
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
processEvents};
ProcessCreationEvents
| where FileName in~('cmd.exe','ftp.exe','schtasks.exe','powershell.exe','rundll32.exe','regsvr32.exe','msiexec.exe')
| where ProcessCommandLine contains ":\\recycler"
| project TimeGenerated, ComputerName, ProcessCommandLine, InitiatingProcessFileName
// Name: Malware in the recycle bin.
//
// Description: finding attackers hiding malware in the recycle bin.
// Read more here: https://azure.microsoft.com/en-us/blog/how-azure-security-center-helps-reveal-a-cyberattack/
//
// Severity: Medium
//
// QueryFrequency: 24
//
// QueryPeriod: 24
//
// AlertTriggerOperator: gt
//
// AlertTriggerThreshold: 0
//
// Data source: SecurityEvent
//
// Techniques: #Execution, #Defense Evasion
//
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
processEvents};
ProcessCreationEvents
| where FileName in~('cmd.exe','ftp.exe','schtasks.exe','powershell.exe','rundll32.exe','regsvr32.exe','msiexec.exe')
| where ProcessCommandLine contains ":\\recycler"
| project TimeGenerated, ComputerName, ProcessCommandLine, InitiatingProcessFileName

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

@ -1,32 +1,32 @@
//Provides a summary view of a given account's activity
//For use when investigating an account that has been identified as having associated suspect activity or been otherwise compromised.
//All office activity by UserName using UI to set Time range
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
let GetAllOfficeActivityByUserName = (UserName:string){
OfficeActivity
| where UserKey contains UserName or UserId contains UserName
| order by TimeGenerated desc
};
GetAllOfficeActivityByUserName("admin@M365x411654") //Example of function being called
//All office activity by UserName where Time range is set in the function call
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
let GetAllOfficeActivityByUserName = (StartTime:datetime, EndTime:datetime, UserName:string){
OfficeActivity
| where UserKey contains UserName or UserId contains UserName
| where TimeGenerated between (StartTime .. EndTime)
| order by TimeGenerated desc
};
GetAllOfficeActivityByUserName(datetime('2018-08-01T10:02:51.000'),datetime('2018-08-22T10:02:51.000'), "admin@M365x411654") //Example of function being called
//All office activity by UserName with 6 hour window around event time that is passed into the function
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
let GetAllOfficeActivityByUserName = (suspiciousEventTime:datetime, UserName:string){
let StartTime = suspiciousEventTime-6d;
let EndTime = suspiciousEventTime+6h;
OfficeActivity
| where UserKey contains UserName or UserId contains UserName
| where TimeGenerated between (StartTime .. EndTime)
| order by TimeGenerated desc
};
//GetAllOfficeActivityByUserName(datetime('2018-08-19T10:02:51.000'), "admin@M365x411654") //Example of function being called
//Provides a summary view of a given account's activity
//For use when investigating an account that has been identified as having associated suspect activity or been otherwise compromised.
//All office activity by UserName using UI to set Time range
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
let GetAllOfficeActivityByUserName = (UserName:string){
OfficeActivity
| where UserKey contains UserName or UserId contains UserName
| order by TimeGenerated desc
};
GetAllOfficeActivityByUserName("admin@M365x411654") //Example of function being called
//All office activity by UserName where Time range is set in the function call
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
let GetAllOfficeActivityByUserName = (StartTime:datetime, EndTime:datetime, UserName:string){
OfficeActivity
| where UserKey contains UserName or UserId contains UserName
| where TimeGenerated between (StartTime .. EndTime)
| order by TimeGenerated desc
};
GetAllOfficeActivityByUserName(datetime('2018-08-01T10:02:51.000'),datetime('2018-08-22T10:02:51.000'), "admin@M365x411654") //Example of function being called
//All office activity by UserName with 6 hour window around event time that is passed into the function
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
let GetAllOfficeActivityByUserName = (suspiciousEventTime:datetime, UserName:string){
let StartTime = suspiciousEventTime-6d;
let EndTime = suspiciousEventTime+6h;
OfficeActivity
| where UserKey contains UserName or UserId contains UserName
| where TimeGenerated between (StartTime .. EndTime)
| order by TimeGenerated desc
};
//GetAllOfficeActivityByUserName(datetime('2018-08-19T10:02:51.000'), "admin@M365x411654") //Example of function being called

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

@ -1,30 +1,30 @@
// Shows accounts that have logged onto a host for the first time - this may clearly be benign activity but an account logging onto multiple hosts for the first time can also be used to look for evidence of that account being used to move laterally across a network.
// Hosts with new logons - ie first time an account has logged onto a host
// Tags: #LateralMovement
let LogonEvents=()
{
let logonSuccess=SecurityEvent
| where EventID==4624
| project EventTime=TimeGenerated, ComputerName=Computer,AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress,ActionType="Logon";
let logonFail=SecurityEvent
| where EventID==4625
| project EventTime=TimeGenerated, ComputerName=Computer,AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress, ActionType="LogonFailure";
logonFail
| union logonSuccess;
};
LogonEvents
| where EventTime >= ago(30d)
| where ActionType == "Logon"
| summarize count() by ComputerName, AccountName
| where AccountName !startswith "Dnz" // DEMO - filter out a known account from baseline
| join kind=leftouter
(
LogonEvents
| where EventTime >= ago(1d)
| where ActionType == "Logon"
| summarize count() by ComputerName, AccountName
)
on ComputerName
| where AccountName != AccountName1
| summarize HostCount=dcount(ComputerName) by AccountName1
| render piechart
// Shows accounts that have logged onto a host for the first time - this may clearly be benign activity but an account logging onto multiple hosts for the first time can also be used to look for evidence of that account being used to move laterally across a network.
// Hosts with new logons - ie first time an account has logged onto a host
// Tags: #LateralMovement
let LogonEvents=()
{
let logonSuccess=SecurityEvent
| where EventID==4624
| project EventTime=TimeGenerated, ComputerName=Computer,AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress,ActionType="Logon";
let logonFail=SecurityEvent
| where EventID==4625
| project EventTime=TimeGenerated, ComputerName=Computer,AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress, ActionType="LogonFailure";
logonFail
| union logonSuccess;
};
LogonEvents
| where EventTime >= ago(30d)
| where ActionType == "Logon"
| summarize count() by ComputerName, AccountName
| where AccountName !startswith "Dnz" // DEMO - filter out a known account from baseline
| join kind=leftouter
(
LogonEvents
| where EventTime >= ago(1d)
| where ActionType == "Logon"
| summarize count() by ComputerName, AccountName
)
on ComputerName
| where AccountName != AccountName1
| summarize HostCount=dcount(ComputerName) by AccountName1
| render piechart

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

@ -1,85 +1,85 @@
// Shows fail user logons divided in to account names in attempts. Shows 5 top account names and others are named 'Other'.
// Tags: #Initial Access #LateralMovement #Persistence
let top5 = SecurityEvent
| where EventID == 4625 and AccountType == 'User'
| extend Account_Name = extract(@"^(.*\\)?([^@]*)(@.*)?$", 2, tolower(Account))
| summarize Attempts = count() by Account_Name
| where Account_Name != ""
| top 5 by Attempts
| summarize makelist(Account_Name);
SecurityEvent
| where EventID == 4625 and AccountType == 'User'
| extend Name = extract(@"^(.*\\)?([^@]*)(@.*)?$", 2, tolower(Account))
| extend Account_Name = iff(Name in (top5), Name, "Other")
| where Account_Name != ""
| summarize Attempts = count() by Account_Name
// Shows 10 most suspicious IP's that attempted to logon. First summarizes amount of success and fail logons to number of unique accounts per IP.
// Must have at least 1 failure, If at least 1 succeeded logon - order by percent between succeeded logons to overall attempts.
// IF no logon has succeeded - Order by number of attempts and unique accounts.
// Tags: #Initial Access #LateralMovement #Persistence
SecurityEvent
| where AccountType == "User"
| where EventID in (4624, 4625)
| summarize Unique_Accounts = dcount(Account), Attempts = count(), Succeeded=countif(EventID == 4624), Failed=countif(EventID == 4625) by IpAddress
| where Failed > 0
| order by Succeeded>0, todouble(Succeeded)/Attempts asc, Attempts desc
| project IP = IpAddress, Succeeded, Attempts, Unique_Accounts
| take 10
| order by Unique_Accounts desc
// Name: Summary of user logons by logon type
// Description: Comparing succesful and nonsuccessful logon attempts can be used to identify attempts to move laterally within the environment with the intention of discovering credentials and sensitive data.
// Tags: #Initial Access #LateralMovement #Persistence
SecurityEvent
| where EventID in (4624, 4625)
| where AccountType == "User"
| summarize Amount = count() by LogonTypeName
// Name: Summary of failed user logons by reason of failure
// Description: A summary of failed logons can be used to infer lateral movement with the intention of discovering credentials and sensitive data.
// Tags: #Initial Access #LateralMovement #Persistence
SecurityEvent
| where AccountType == 'User' and EventID == 4625
| extend Reason = case(
SubStatus == '0xc000005e', 'No logon servers available to service the logon request',
SubStatus == '0xc0000062', 'Account name is not properly formatted',
SubStatus == '0xc0000064', 'Account name does not exist',
SubStatus == '0xc000006a', 'Incorrect password',
SubStatus == '0xc000006d', 'Bad user name or password',
SubStatus == '0xc000006f', 'User logon blocked by account restriction',
SubStatus == '0xc000006f', 'User logon outside of restricted logon hours',
SubStatus == '0xc0000070', 'User logon blocked by workstation restriction',
SubStatus == '0xc0000071', 'Password has expired',
SubStatus == '0xc0000072', 'Account is disabled',
SubStatus == '0xc0000133', 'Clocks between DC and other computer too far out of sync',
SubStatus == '0xc000015b', 'The user has not been granted the requested logon right at this machine',
SubStatus == '0xc0000193', 'Account has expirated',
SubStatus == '0xc0000224', 'User is required to change password at next logon',
SubStatus == '0xc0000234', 'Account is currently locked out',
strcat('Unknown reason substatus: ', SubStatus))
| summarize count() by Reason
// List of accounts locked out (event id 4740)
// Tags: #Initial Access #LateralMovement #Persistence
SecurityEvent
| where EventID == 4740
// Attackers often move to the next step which can loosely be called network propagation stage.
// The goal of the Network Propagation phase is to identify and move to desired systems within the target environment with the intention of discovering credentials and sensitive data.
// Sometimes as part of this one might see one account being used to log in on unusually high number of machines in the environment or lot of different account authentication requests coming from one machine.
// Tags: #Initial Access #LateralMovement #Persistence
SecurityEvent
| where EventID == 4624
| where AccountType == "User"
| where TimeGenerated >= ago(1d)
| summarize IndividualAccounts = dcount(Account) by Computer
| where IndividualAccounts > 4
// Shows fail user logons divided in to account names in attempts. Shows 5 top account names and others are named 'Other'.
// Tags: #Initial Access #LateralMovement #Persistence
let top5 = SecurityEvent
| where EventID == 4625 and AccountType == 'User'
| extend Account_Name = extract(@"^(.*\\)?([^@]*)(@.*)?$", 2, tolower(Account))
| summarize Attempts = count() by Account_Name
| where Account_Name != ""
| top 5 by Attempts
| summarize makelist(Account_Name);
SecurityEvent
| where EventID == 4625 and AccountType == 'User'
| extend Name = extract(@"^(.*\\)?([^@]*)(@.*)?$", 2, tolower(Account))
| extend Account_Name = iff(Name in (top5), Name, "Other")
| where Account_Name != ""
| summarize Attempts = count() by Account_Name
// Shows 10 most suspicious IP's that attempted to logon. First summarizes amount of success and fail logons to number of unique accounts per IP.
// Must have at least 1 failure, If at least 1 succeeded logon - order by percent between succeeded logons to overall attempts.
// IF no logon has succeeded - Order by number of attempts and unique accounts.
// Tags: #Initial Access #LateralMovement #Persistence
SecurityEvent
| where AccountType == "User"
| where EventID in (4624, 4625)
| summarize Unique_Accounts = dcount(Account), Attempts = count(), Succeeded=countif(EventID == 4624), Failed=countif(EventID == 4625) by IpAddress
| where Failed > 0
| order by Succeeded>0, todouble(Succeeded)/Attempts asc, Attempts desc
| project IP = IpAddress, Succeeded, Attempts, Unique_Accounts
| take 10
| order by Unique_Accounts desc
// Name: Summary of user logons by logon type
// Description: Comparing succesful and nonsuccessful logon attempts can be used to identify attempts to move laterally within the environment with the intention of discovering credentials and sensitive data.
// Tags: #Initial Access #LateralMovement #Persistence
SecurityEvent
| where EventID in (4624, 4625)
| where AccountType == "User"
| summarize Amount = count() by LogonTypeName
// Name: Summary of failed user logons by reason of failure
// Description: A summary of failed logons can be used to infer lateral movement with the intention of discovering credentials and sensitive data.
// Tags: #Initial Access #LateralMovement #Persistence
SecurityEvent
| where AccountType == 'User' and EventID == 4625
| extend Reason = case(
SubStatus == '0xc000005e', 'No logon servers available to service the logon request',
SubStatus == '0xc0000062', 'Account name is not properly formatted',
SubStatus == '0xc0000064', 'Account name does not exist',
SubStatus == '0xc000006a', 'Incorrect password',
SubStatus == '0xc000006d', 'Bad user name or password',
SubStatus == '0xc000006f', 'User logon blocked by account restriction',
SubStatus == '0xc000006f', 'User logon outside of restricted logon hours',
SubStatus == '0xc0000070', 'User logon blocked by workstation restriction',
SubStatus == '0xc0000071', 'Password has expired',
SubStatus == '0xc0000072', 'Account is disabled',
SubStatus == '0xc0000133', 'Clocks between DC and other computer too far out of sync',
SubStatus == '0xc000015b', 'The user has not been granted the requested logon right at this machine',
SubStatus == '0xc0000193', 'Account has expirated',
SubStatus == '0xc0000224', 'User is required to change password at next logon',
SubStatus == '0xc0000234', 'Account is currently locked out',
strcat('Unknown reason substatus: ', SubStatus))
| summarize count() by Reason
// List of accounts locked out (event id 4740)
// Tags: #Initial Access #LateralMovement #Persistence
SecurityEvent
| where EventID == 4740
// Attackers often move to the next step which can loosely be called network propagation stage.
// The goal of the Network Propagation phase is to identify and move to desired systems within the target environment with the intention of discovering credentials and sensitive data.
// Sometimes as part of this one might see one account being used to log in on unusually high number of machines in the environment or lot of different account authentication requests coming from one machine.
// Tags: #Initial Access #LateralMovement #Persistence
SecurityEvent
| where EventID == 4624
| where AccountType == "User"
| where TimeGenerated >= ago(1d)
| summarize IndividualAccounts = dcount(Account) by Computer
| where IndividualAccounts > 4

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

@ -1,29 +1,29 @@
//Shows authentication volume by user agent and IP address.
//Tracking via user agent is one way to differentiate between types of connecting device.
//In homogeneous enterprise environments the user agent associated with an attacker device may stand out as unusual.
//Examining authentications by new devices or originating from new IPs is a potential avenue to discover unauthorized access.
//Similarly new device types (user agents) on a known IP address is potentially suspect.
// Office - authentications by UA & IP (likely only manageable for small tenants)
// Tags: #Discovery #LateralMovement #Collection
OfficeActivity
| where RecordType in ("AzureActiveDirectoryAccountLogon", "AzureActiveDirectoryStsLogon")
| where Operation startswith "UserLoggedIn"
| extend UserAgent = extractjson("$[0].Value", ExtendedProperties, typeof(string))
| project Operation, UserId, TimeGenerated , UserAgent, ClientIP
| summarize userAgentCount=count() by UserAgent, ClientIP
| sort by userAgentCount desc;
//Shows authentication volume by user agent.
//Tracking via user agent is one way to differentiate between types of connecting device.
//In homogeneous enterprise environments the user agent associated with an attacker device may stand out as unusual.
//Examining authentications by new devices is a potential avenue to discover unauthorized access.
// Tags: #Discovery #LateralMovement #Collection
OfficeActivity
| where RecordType in ("AzureActiveDirectoryAccountLogon", "AzureActiveDirectoryStsLogon")
| where Operation startswith "UserLoggedIn"
| extend UserAgent = extractjson("$[0].Value", ExtendedProperties, typeof(string))
| extend machineIndex=indexof(UserAgent, "machine_id")
| extend UserAgent = substring(UserAgent, 0, machineIndex)
| project Operation, UserId, TimeGenerated , UserAgent
| summarize userAgentCount=count() by UserAgent
| sort by userAgentCount desc;
//Shows authentication volume by user agent and IP address.
//Tracking via user agent is one way to differentiate between types of connecting device.
//In homogeneous enterprise environments the user agent associated with an attacker device may stand out as unusual.
//Examining authentications by new devices or originating from new IPs is a potential avenue to discover unauthorized access.
//Similarly new device types (user agents) on a known IP address is potentially suspect.
// Office - authentications by UA & IP (likely only manageable for small tenants)
// Tags: #Discovery #LateralMovement #Collection
OfficeActivity
| where RecordType in ("AzureActiveDirectoryAccountLogon", "AzureActiveDirectoryStsLogon")
| where Operation startswith "UserLoggedIn"
| extend UserAgent = extractjson("$[0].Value", ExtendedProperties, typeof(string))
| project Operation, UserId, TimeGenerated , UserAgent, ClientIP
| summarize userAgentCount=count() by UserAgent, ClientIP
| sort by userAgentCount desc;
//Shows authentication volume by user agent.
//Tracking via user agent is one way to differentiate between types of connecting device.
//In homogeneous enterprise environments the user agent associated with an attacker device may stand out as unusual.
//Examining authentications by new devices is a potential avenue to discover unauthorized access.
// Tags: #Discovery #LateralMovement #Collection
OfficeActivity
| where RecordType in ("AzureActiveDirectoryAccountLogon", "AzureActiveDirectoryStsLogon")
| where Operation startswith "UserLoggedIn"
| extend UserAgent = extractjson("$[0].Value", ExtendedProperties, typeof(string))
| extend machineIndex=indexof(UserAgent, "machine_id")
| extend UserAgent = substring(UserAgent, 0, machineIndex)
| project Operation, UserId, TimeGenerated , UserAgent
| summarize userAgentCount=count() by UserAgent
| sort by userAgentCount desc;

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

@ -0,0 +1,7 @@
// If we also wanted to see what alerts fired on these machines we could extend the above query and join them with the SecurityAlerts table from Azure Security Center.
// Azure Security Center must be enabled for this query to be valid
| join (SecurityAlert
| extend ExtProps=parsejson(ExtendedProperties)
| extend Computer=toupper(tostring(ExtProps["Compromised Host"]))
)
on Computer

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

@ -0,0 +1,14 @@
// Name: Summary of users creating new user accounts
//
// Description: creating new user accounts is a privileged activity that may be abused by attackers to provide persistent access.
// Reviewing which user accounts have been created, and by whom, can help detect attacker attempts to provide themselves with backdoor access to data.
//
// Data source: OfficeActivity
//
// Techniques: #Persistence
//
OfficeActivity
| where Operation == "Add user."
| project addedBy=UserId, newUser=OfficeObjectId
| summarize newUserCount=dcount(newUser) by addedBy
| render barchart

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

@ -1,10 +1,15 @@
// Name: Accounts and User Agents associated with multiple IPs.
// Name: Accounts and User Agents associated with multiple IPs in Office Azure Active Directory authentications.
//
// Description: summary of users/user agents associated with authentications from multiple IPs within a short timeframe.
// This query computes and joins two tables to highlight IPs associated with multiple authentications:
// 1- UserAgents seen in authentications from multiple IPs within short timeframe
// 2- User Ids seen authenticated from multiple IPs
// The time window join looks for instances of a small elpased time between logons.
// Tags: #InitialAccess
//
// Data source: OfficeActivity
//
// Techniques: #InitialAccess
//
let timeRange=ago(7d);
let officeAuthentications =
OfficeActivity

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

@ -0,0 +1,23 @@
// Name: sharepoint downloads from previously unseen IP address.
//
// Description: Shows volume of documents uploaded to or downloaded from Sharepoint by new IP addresses.
// In stable environments such connections by new IPs may be unauthorized, especially if associated with spikes in volume which could be associated with large-scale document exfiltration.
//
// Data source: OfficeActivity
//
// Techniques: #Exfiltration
//
let historicalActivity=
OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated between(ago(30d)..ago(7d))
| summarize historicalCount=count() by ClientIP;
let recentActivity = OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated > ago(1d)
| summarize recentCount=count() by ClientIP;
recentActivity | join kind= leftanti (
historicalActivity
) on ClientIP;

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

@ -0,0 +1,25 @@
// Name: sharepoint downloads from devices associated with previously unseen user agents.
//
// Description: tracking via user agent is one way to differentiate between types of connecting device.
// In homogeneous enterprise environments the user agent associated with an attacker device may stand out as unusual.
// In stable environments such connections by new IPs may be unauthorized, especially if associated with spikes in volume
// which could be associated with large-scale document exfiltration.
//
// Data source: OfficeActivity
//
// Techniques: #Exfiltration
//
let historicalActivity=
OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated between(ago(30d)..ago(7d))
| summarize historicalCount=count() by UserAgent;
let recentActivity = OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated > ago(1d)
| summarize recentCount=count() by UserAgent;
recentActivity | join kind= leftouter (
historicalActivity
) on UserAgent;

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

@ -0,0 +1,22 @@
// Name: New user agents associated with a clientIP for sharepoint file uploads/downloads
//
// Description: New user agents associated with a clientIP for sharepoint file uploads/downloads.
//
// Data source: OfficeActivity
//
// Techniques: #Exfiltration
//
let historicalUA=
OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated between(ago(30d)..ago(7d))
| summarize by ClientIP, UserAgent;
let recentUA = OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated > ago(1d)
| summarize by ClientIP, UserAgent;
recentUA | join kind=leftanti (
historicalUA
) on ClientIP, UserAgent;

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

@ -1,5 +1,11 @@
// cscript script daily summary breakdown
// Tags: #Execution
// Name: cscript script daily summary breakdown
//
// Description: breakdown of scripts running in the environment
//
// Data source: SecurityEvent
//
// Techniques: #Execution
//
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688

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

@ -1,17 +1,23 @@
// The query finds attempts to list users or groups using Net commands
// Tags: #Initial Access #Execution #Persistence #Lateral Movement #Discovery
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
FolderPath = "",
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
processEvents};
ProcessCreationEvents
| where FileName == 'net.exe' and AccountName != "" and ProcessCommandLine !contains '\\' and ProcessCommandLine !contains '/add'
| where (ProcessCommandLine contains ' user ' or ProcessCommandLine contains ' group ') and (ProcessCommandLine endswith ' /do' or ProcessCommandLine endswith ' /domain')
| extend Target = extract("(?i)[user|group] (\"*[a-zA-Z0-9-_ ]+\"*)", 1, ProcessCommandLine) | filter Target != ''
| project AccountName, Target, ProcessCommandLine, ComputerName, TimeGenerated
// Name: Enumeration of users and groups
// Description: finds attempts to list users or groups using the built-in Windows 'net' tool
// Data source: SecurityEvent
// Techniques: #Discovery
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
FolderPath = "",
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
processEvents};
ProcessCreationEvents
| where FileName == 'net.exe' and AccountName != "" and ProcessCommandLine !contains '\\' and ProcessCommandLine !contains '/add'
| where (ProcessCommandLine contains ' user ' or ProcessCommandLine contains ' group ') and (ProcessCommandLine endswith ' /do' or ProcessCommandLine endswith ' /domain')
| extend Target = extract("(?i)[user|group] (\"*[a-zA-Z0-9-_ ]+\"*)", 1, ProcessCommandLine) | filter Target != ''
| project AccountName, Target, ProcessCommandLine, ComputerName, TimeGenerated
| sort by AccountName, Target

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

@ -0,0 +1,21 @@
// Name: masquerading files.
// Description: Malware writers often use windows system process names for their malicious process names to make them blend
// in with other legitimate commands that the Windows system executes.
// An analyst can create a simple query looking for a process named svchost.exe.
// It is recommended to filter out well-known security identifiers (SIDs) that are used to launch the legitimate svchost.exe process.
// The query also filters out the legitimate locations from which svchost.exe is launched.
//
// Data source: SecurityEvent
//
// Techniques: #Execution, #Defense Evasion
//
SecurityEvent
| where ProcessName contains "svchost.exe"
| where SubjectUserSid != "S-1-5-18"
| where SubjectUserSid != "S-1-5-19"
| where SubjectUserSid != "S-1-5-20"
| where NewProcessName !contains ":\\Windows\\System32"
| where NewProcessName !contains ":\\Windows\\Syswow64"

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

@ -1,21 +1,26 @@
// Name: Summary of users created using uncommon & undocumented commandline switches
// Description: Summarizes users of uncommon & undocumented commandline switches to create persistance
// User accounts may be created to achieve persistence on a machine.
// Read more here: https://attack.mitre.org/wiki/Technique/T1136
// Query for users being created using "net user" command
// "net user" commands are noisy, so needs to be joined with another signal -
// e.g. in this example we look (e.g. /ad instead of /add)
// Tags: #InitialAccess #Execution #LateralMovement #Persistance #DefenseEvasion
SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName,
AccountDomain=SubjectDomainName, FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
FolderPath = "", InitiatingProcessFileName=ParentProcessName,
InitiatingProcessCommandLine="",InitiatingProcessParentFileName=""
| where FileName in~ ("net.exe", "net1.exe")
| parse kind=regex flags=iU ProcessCommandLine with * "user " CreatedUser " " * "/ad"
| where not(FileName =~ "net1.exe" and InitiatingProcessFileName =~ "net.exe" and replace("net", "net1", InitiatingProcessCommandLine) =~ ProcessCommandLine)
| extend CreatedOnLocalMachine=(ProcessCommandLine !contains "/do")
| where ProcessCommandLine contains "/add" or (CreatedOnLocalMachine == 0 and ProcessCommandLine !contains "/domain")
| summarize MachineCount=dcount(ComputerName) by CreatedUser, CreatedOnLocalMachine, InitiatingProcessFileName, FileName, ProcessCommandLine, InitiatingProcessCommandLine
// Name: Summary of users created using uncommon & undocumented commandline switches
//
// Description: Summarizes uses of uncommon & undocumented commandline switches to create persistence
// User accounts may be created to achieve persistence on a machine.
// Read more here: https://attack.mitre.org/wiki/Technique/T1136
// Query for users being created using "net user" command
// "net user" commands are noisy, so needs to be joined with another signal -
// e.g. in this example we look for some undocumented variations (e.g. /ad instead of /add)
//
// Data source: SecurityEvent
//
// Techniques: #Persistence
//
SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName,
AccountDomain=SubjectDomainName, FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
FolderPath = "", InitiatingProcessFileName=ParentProcessName,
InitiatingProcessCommandLine="",InitiatingProcessParentFileName=""
| where FileName in~ ("net.exe", "net1.exe")
| parse kind=regex flags=iU ProcessCommandLine with * "user " CreatedUser " " * "/ad"
| where not(FileName =~ "net1.exe" and InitiatingProcessFileName =~ "net.exe" and replace("net", "net1", InitiatingProcessCommandLine) =~ ProcessCommandLine)
| extend CreatedOnLocalMachine=(ProcessCommandLine !contains "/do")
| where ProcessCommandLine contains "/add" or (CreatedOnLocalMachine == 0 and ProcessCommandLine !contains "/domain")
| summarize MachineCount=dcount(ComputerName) by CreatedUser, CreatedOnLocalMachine, InitiatingProcessFileName, FileName, ProcessCommandLine, InitiatingProcessCommandLine

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

@ -1,19 +1,25 @@
// Finds PowerShell execution events that could involve a download.
// Tags: #Initial Access, #Execution, #Persistence
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
processEvents};
ProcessCreationEvents
| where FileName in~ ("powershell.exe", "powershell_ise.exe")
| where ProcessCommandLine has "Net.WebClient"
or ProcessCommandLine has "DownloadFile"
or ProcessCommandLine has "Invoke-WebRequest"
or ProcessCommandLine has "Invoke-Shellcode"
or ProcessCommandLine contains "http:"
| project TimeGenerated, ComputerName, InitiatingProcessFileName, FileName, ProcessCommandLine
// Name: powershell downloads
//
// Description: Finds PowerShell execution events that could involve a download
//
// Data source: SecurityEvent
//
// Techniques: #Initial Access, #Execution, #Persistence
//
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
processEvents};
ProcessCreationEvents
| where FileName in~ ("powershell.exe", "powershell_ise.exe")
| where ProcessCommandLine has "Net.WebClient"
or ProcessCommandLine has "DownloadFile"
or ProcessCommandLine has "Invoke-WebRequest"
or ProcessCommandLine has "Invoke-Shellcode"
or ProcessCommandLine contains "http:"
| project TimeGenerated, ComputerName, InitiatingProcessFileName, FileName, ProcessCommandLine
| top 100 by TimeGenerated

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

@ -1,9 +1,15 @@
// Identify and decode new encoded powershell scripts this week versus previous fortnight - generic
// Tags: #Initial Access, #Execution, #Persistence
// Name: new powershell scripts encoded on the commandline
//
// Description: Identify and decode new encoded powershell scripts this week versus previous fortnight
//
// Data source: SecurityEvent
//
// Techniques: #Initial Access, #Execution, #Persistence
//
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName,AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";

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

@ -1,40 +1,48 @@
// Shows the rarest processes seen running for the first time. (Performs best over longer time ranges - eg 3+ days rather than 24 hours!)
// These new processes could be benign new programs installed on hosts;
// However, especially in normally stable environments, these new processes could provide an indication of an unauthorized/malicious binary that has been installed and run.
// Reviewing the wider context of the logon sessions in which these binaries ran can provide a good starting point for identifying possible attacks.
// Uncommon processes/files - bottom 5%
// Tags: #Initial Access, #Execution, #Persistence, #Privilege Escalation, #Credential Access, #Discovery, #Lateral Movement, #Collection, #Exfiltration, #Command and Control
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
// filter out common randomly named files related to MSI installers and browsers
| where not(NewProcessName matches regex @"Temp\\[0-9]{1}\\TRA[0-9A-Fa-f]{3}.tmp")
| where not(NewProcessName matches regex @"Temp\\[0-9]{1}\\TRA[0-9A-Fa-f]{4}.tmp")
| where not(NewProcessName matches regex @"Installer\\MSI[0-9A-Fa-f]{3}\.tmp")
| where not(NewProcessName matches regex @"Installer\\MSI[0-9A-Fa-f]{4}\.tmp")
| project TimeGenerated,
ComputerName=Computer,
AccountName=SubjectUserName,
AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
InitiatingProcessFileName=ParentProcessName,
InitiatingProcessCommandLine="",
InitiatingProcessParentFileName="";
processEvents;
};
let normalizedProcesses = ProcessCreationEvents
| project TimeGenerated, FileName = replace("[0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12}", "<guid>", FileName) // normalize guids
| project TimeGenerated, FileName=replace(@'\d', 'n', FileName); // normalize digits away
let freqs = normalizedProcesses
| summarize frequency=count() by FileName
| join kind= leftouter (
normalizedProcesses
| summarize Since=min(TimeGenerated), LastSeen=max(TimeGenerated) by FileName
) on FileName;
freqs
| where frequency <= toscalar( freqs | serialize | project frequency | summarize percentiles(frequency, 5))
| order by frequency asc
| project FileName, frequency, Since, LastSeen
// restrict results to unusual processes seen in last day
// Name: uncommon processes - bottom 5%
//
// Description: Identify and decode new encoded powershell scripts this week versus previous fortnight
//
// Description:
// Shows the rarest processes seen running for the first time. (Performs best over longer time ranges - eg 3+ days rather than 24 hours!)
// These new processes could be benign new programs installed on hosts;
// However, especially in normally stable environments, these new processes could provide an indication of an unauthorized/malicious binary that has been installed and run.
// Reviewing the wider context of the logon sessions in which these binaries ran can provide a good starting point for identifying possible attacks.
//
// Data source: SecurityEvent
//
// Techniques: #Initial Access, #Execution, #Persistence, #Privilege Escalation, #Credential Access, #Discovery, #Lateral Movement, #Collection, #Exfiltration, #Command and Control
//
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
// filter out common randomly named files related to MSI installers and browsers
| where not(NewProcessName matches regex @"Temp\\[0-9]{1}\\TRA[0-9A-Fa-f]{3}\.tmp")
| where not(NewProcessName matches regex @"Temp\\[0-9]{1}\\TRA[0-9A-Fa-f]{4}\.tmp")
| where not(NewProcessName matches regex @"Installer\\MSI[0-9A-Fa-f]{3}\.tmp")
| where not(NewProcessName matches regex @"Installer\\MSI[0-9A-Fa-f]{4}\.tmp")
| project TimeGenerated,
ComputerName=Computer,
AccountName=SubjectUserName,
AccountDomain=SubjectDomainName,
FileName=tostring(split(NewProcessName, '\\')[-1]),
ProcessCommandLine = CommandLine,
InitiatingProcessFileName=ParentProcessName,
InitiatingProcessCommandLine="",
InitiatingProcessParentFileName="";
processEvents;
};
let normalizedProcesses = ProcessCreationEvents
| project TimeGenerated, FileName = replace("[0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12}", "<guid>", FileName) // normalize guids
| project TimeGenerated, FileName=replace(@'\d', 'n', FileName); // normalize digits away
let freqs = normalizedProcesses
| summarize frequency=count() by FileName
| join kind= leftouter (
normalizedProcesses
| summarize Since=min(TimeGenerated), LastSeen=max(TimeGenerated) by FileName
) on FileName;
freqs
| where frequency <= toscalar( freqs | serialize | project frequency | summarize percentiles(frequency, 5))
| order by frequency asc
| project FileName, frequency, Since, LastSeen
// restrict results to unusual processes seen in last day
| where LastSeen >= ago(1d)

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

@ -1,7 +1,12 @@
// Name: Anomalous Azure AD apps based on authentication location
// Name: Anomalous Azure Active Directory apps based on authentication location
//
// Description: This query over Azure AD sign-in activity highlights Azure AD apps with
// an unusually high ratio of distinct geolocations versus total number of authentications
// Tags: #InitialAccess
//
// Data source: SigninLogs
//
// Techniques: #InitialAccess
//
let timeRange=ago(14d);
let azureSignIns =
SigninLogs

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

@ -1,8 +1,12 @@
// Name: azure AD signins from new locations.
// Description: New AzureAD signin locations today versus historical Azure AD signin data
// In the case of password spraying or brute force attacks
// one might see authentication attempts for many accounts from a new location.
// Tags: #InitialAccess
// Name: Azure Active Directory signins from new locations.
//
// Description: New Azure Active Directory signin locations today versus historical Azure Active Directory signin data
// In the case of password spraying or brute force attacks one might see authentication attempts for many accounts from a new location.
//
// Data source: SigninLogs
//
// Techniques: #InitialAccess
//
SigninLogs
| where TimeGenerated >= ago(1d)
| summarize perIdentityAuthCount=count() by Identity, locationString= strcat(tostring(LocationDetails["countryOrRegion"]), "/", tostring(LocationDetails["state"]), "/", tostring(LocationDetails["city"]), ";" , tostring(LocationDetails["geoCoordinates"]))

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

@ -1,7 +1,12 @@
// Name: Signin burst from multiple locations
// Description: This query over Azure AD sign-in activity highlights accounts associated
// with multiple authentications from different geographical locations in a short space of time
// Tags: #InitialAccess
// Name: Azure Active Directory sign-in burst from multiple locations
//
// Description: This query over Azure Active Directory sign-in activity highlights accounts associated
// with multiple authentications from different geographical locations in a short space of time.
//
// Data source: SigninLogs
//
// Techniques: #InitialAccess
//
let timeRange=ago(10d);
let signIns = SigninLogs
| where TimeGenerated >= timeRange

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

@ -1,24 +0,0 @@
// Process executed from binary hidden in Base64 encoded file. Encoding malicious software is a technique to obfuscate files from detection.
// The first ProcessCommandLine component is looking for Python decoding base64
// The second ProcesssCommandLine component is looking for the Bash/sh commandline base64 decoding tool
// The third one is looking for Ruby decoding base64
// Tags: #Initial Access, #Execution, #Defense Evasion
let ProcessCreationEvents=() {
let processEvents=SecurityEvent
| where EventID==4688
| project EventTime=TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
FileName=reverse(substring(reverse(NewProcessName), 0, indexof(reverse(NewProcessName), "\\"))), // convert SecurityEvents raw schema to get FileName & CommandLine
ProcessCommandLine = CommandLine,
FolderPath = "",
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
processEvents ;
};
ProcessCreationEvents
| where EventTime > ago(14d)
| where ProcessCommandLine contains ".decode('base64')"
or ProcessCommandLine contains "base64 --decode"
or ProcessCommandLine contains ".decode64("
| project EventTime , ComputerName , FileName , ProcessCommandLine , InitiatingProcessCommandLine
| top 100 by EventTime

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

@ -1,30 +0,0 @@
// Malware writers often use windows system process names for their malicious process names to make them blend in with other legitimate commands that the Windows system executes.
// an analyst can create a simple query looking for a process named Svchost.exe.
// It is recommended to filter out well-known security identifiers (SIDs) that are used to launch the legitimate svchost.exe process.
// The query also filters out the legitimate locations from which svchost.exe is launched.
// Tags: #Execution, #Defense Evasion
SecurityEvent
| where TimeGenerated >= ago(2d)
| where ProcessName contains "svchost.exe"
| where SubjectUserSid != "S-1-5-18"
| where SubjectUserSid != "S-1-5-19"
| where SubjectUserSid != "S-1-5-20"
| where NewProcessName !contains "C:\\Windows\\System32"
| where NewProcessName !contains "C:\\Windows\\Syswow64"
// If we also wanted to see what alerts fired on these machines we could extend the above query and join them with the SecurityAlerts table from Azure Security Center.
// Azure Security Center must be enabled for this query to be valid
// Tags: #Execution
SecurityEvent
| where EventID == 4624
| where AccountType == "User"
| where TimeGenerated >= ago(1d)
| extend Computer = toupper(Computer)
| summarize IndividualAccounts = dcount(Account) by Computer
| where IndividualAccounts > 4
| join (SecurityAlert
| extend ExtProps=parsejson(ExtendedProperties)
| extend Computer=toupper(tostring(ExtProps["Compromised Host"]))
)
on Computer

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

@ -1,59 +0,0 @@
//Shows volume of documents uploaded to or downloaded from Sharepoint by new IP addresses.
//In stable environments such connections by new IPs may be unauthorized, especially if associated with spikes in volume which could be associated with large-scale document exfiltration.
// Tags: #Exfiltration
let historicalActivity=
OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated between(ago(30d)..ago(7d))
| summarize historicalCount=count() by ClientIP;
let recentActivity = OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated > ago(1d)
| summarize recentCount=count() by ClientIP;
recentActivity | join kind= leftanti (
historicalActivity
) on ClientIP;
//Shows volume of documents uploaded to or downloaded from Sharepoint by user agent.
//Tracking via user agent is one way to differentiate between types of connecting device.
//In homogeneous enterprise environments the user agent associated with an attacker device may stand out as unusual.
//In stable environments such connections by new IPs may be unauthorized, especially if associated with spikes in volume which could be associated with large-scale document exfiltration.
// Sharepoint - files downloaded/uploaded by new user agent
// Tags: #Exfiltration
let historicalActivity=
OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated between(ago(30d)..ago(7d))
| summarize historicalCount=count() by UserAgent;
let recentActivity = OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated > ago(1d)
| summarize recentCount=count() by UserAgent;
recentActivity | join kind= leftouter (
historicalActivity
) on UserAgent;
// Sharepoint -New user agents associated with a clientIP for sharepoint file uploads/downloads
// Tags: #Exfiltration
let historicalUA=
OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated between(ago(30d)..ago(7d))
// DEMO | where TimeGenerated between(datetime(2018-05-25)..datetime(2018-05-29 21:00)) // fake history
| summarize by ClientIP, UserAgent;
let recentUA = OfficeActivity
| where RecordType == "SharePointFileOperation"
| where Operation in ("FileDownloaded", "FileUploaded")
| where TimeGenerated > ago(1d)
// DEMO | where TimeGenerated between (datetime(2018-05-29 21:30)..datetime(2018-05-29 21:45))
| summarize by ClientIP, UserAgent;
recentUA | join kind=leftanti (
historicalUA
) on ClientIP, UserAgent;

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

@ -1,9 +0,0 @@
// Name: Summary of users creating new user accounts
// Description: new user accounts may be an attacker providing themselves with backdoor access for some later date.
// an account creating further accounts for the first time may be an indication of compromise
// Tags: #Persistance
OfficeActivity
| where Operation == "Add user."
| project addedBy=UserId, newUser=OfficeObjectId
| summarize newUserCount=dcount(newUser) by addedBy
| render barchart