folder restructure for hunting queries, exploration queries, and built-in alerts aka detections. (#12)
This commit is contained in:
Родитель
d104b28411
Коммит
38faeb1656
|
@ -1,14 +1,31 @@
|
||||||
// Finding base64 encoded PE files header seen in the command line parameters
|
// Name: Base64 encoded Windows executables in process commandlines
|
||||||
// Tags: #Initial Access, #Execution, #Defense Evasion
|
|
||||||
let ProcessCreationEvents=() {
|
// Description: finds instances of base64 encoded PE files header seen in process command line parameter.
|
||||||
let processEvents=SecurityEvent
|
|
||||||
| where EventID==4688
|
// Severity: Medium
|
||||||
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
|
|
||||||
FileName=tostring(split(NewProcessName, '\\')[-1]),
|
// QueryFrequency: 24
|
||||||
ProcessCommandLine = CommandLine,
|
|
||||||
FolderPath = "",
|
// QueryPeriod: 24
|
||||||
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
|
|
||||||
processEvents};
|
// AlertTriggerOperator: gt
|
||||||
ProcessCreationEvents
|
|
||||||
| where ProcessCommandLine contains "TVqQAAMAAAAEAAA"
|
// 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
|
| 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.
|
// Name: 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
|
// Description: finding attackers hiding malware in the recycle bin.
|
||||||
let ProcessCreationEvents=() {
|
// Read more here: https://azure.microsoft.com/en-us/blog/how-azure-security-center-helps-reveal-a-cyberattack/
|
||||||
let processEvents=SecurityEvent
|
//
|
||||||
| where EventID==4688
|
// Severity: Medium
|
||||||
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
|
//
|
||||||
FileName=tostring(split(NewProcessName, '\\')[-1]),
|
// QueryFrequency: 24
|
||||||
ProcessCommandLine = CommandLine,
|
//
|
||||||
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
|
// QueryPeriod: 24
|
||||||
processEvents};
|
//
|
||||||
ProcessCreationEvents
|
// AlertTriggerOperator: gt
|
||||||
| where FileName in~('cmd.exe','ftp.exe','schtasks.exe','powershell.exe','rundll32.exe','regsvr32.exe','msiexec.exe')
|
//
|
||||||
| where ProcessCommandLine contains ":\\recycler"
|
// AlertTriggerThreshold: 0
|
||||||
| project TimeGenerated, ComputerName, ProcessCommandLine, InitiatingProcessFileName
|
//
|
||||||
|
// 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
|
//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.
|
//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
|
//All office activity by UserName using UI to set Time range
|
||||||
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
|
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
|
||||||
let GetAllOfficeActivityByUserName = (UserName:string){
|
let GetAllOfficeActivityByUserName = (UserName:string){
|
||||||
OfficeActivity
|
OfficeActivity
|
||||||
| where UserKey contains UserName or UserId contains UserName
|
| where UserKey contains UserName or UserId contains UserName
|
||||||
| order by TimeGenerated desc
|
| order by TimeGenerated desc
|
||||||
};
|
};
|
||||||
GetAllOfficeActivityByUserName("admin@M365x411654") //Example of function being called
|
GetAllOfficeActivityByUserName("admin@M365x411654") //Example of function being called
|
||||||
|
|
||||||
//All office activity by UserName where Time range is set in the function call
|
//All office activity by UserName where Time range is set in the function call
|
||||||
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
|
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
|
||||||
let GetAllOfficeActivityByUserName = (StartTime:datetime, EndTime:datetime, UserName:string){
|
let GetAllOfficeActivityByUserName = (StartTime:datetime, EndTime:datetime, UserName:string){
|
||||||
OfficeActivity
|
OfficeActivity
|
||||||
| where UserKey contains UserName or UserId contains UserName
|
| where UserKey contains UserName or UserId contains UserName
|
||||||
| where TimeGenerated between (StartTime .. EndTime)
|
| where TimeGenerated between (StartTime .. EndTime)
|
||||||
| order by TimeGenerated desc
|
| 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
|
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
|
//All office activity by UserName with 6 hour window around event time that is passed into the function
|
||||||
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
|
// Tags: #Persistence, #Discovery, #Lateral Movement, #Collection
|
||||||
let GetAllOfficeActivityByUserName = (suspiciousEventTime:datetime, UserName:string){
|
let GetAllOfficeActivityByUserName = (suspiciousEventTime:datetime, UserName:string){
|
||||||
let StartTime = suspiciousEventTime-6d;
|
let StartTime = suspiciousEventTime-6d;
|
||||||
let EndTime = suspiciousEventTime+6h;
|
let EndTime = suspiciousEventTime+6h;
|
||||||
OfficeActivity
|
OfficeActivity
|
||||||
| where UserKey contains UserName or UserId contains UserName
|
| where UserKey contains UserName or UserId contains UserName
|
||||||
| where TimeGenerated between (StartTime .. EndTime)
|
| where TimeGenerated between (StartTime .. EndTime)
|
||||||
| order by TimeGenerated desc
|
| order by TimeGenerated desc
|
||||||
};
|
};
|
||||||
//GetAllOfficeActivityByUserName(datetime('2018-08-19T10:02:51.000'), "admin@M365x411654") //Example of function being called
|
//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.
|
// 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
|
// Hosts with new logons - ie first time an account has logged onto a host
|
||||||
// Tags: #LateralMovement
|
// Tags: #LateralMovement
|
||||||
let LogonEvents=()
|
let LogonEvents=()
|
||||||
{
|
{
|
||||||
let logonSuccess=SecurityEvent
|
let logonSuccess=SecurityEvent
|
||||||
| where EventID==4624
|
| where EventID==4624
|
||||||
| project EventTime=TimeGenerated, ComputerName=Computer,AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress,ActionType="Logon";
|
| project EventTime=TimeGenerated, ComputerName=Computer,AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress,ActionType="Logon";
|
||||||
let logonFail=SecurityEvent
|
let logonFail=SecurityEvent
|
||||||
| where EventID==4625
|
| where EventID==4625
|
||||||
| project EventTime=TimeGenerated, ComputerName=Computer,AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress, ActionType="LogonFailure";
|
| project EventTime=TimeGenerated, ComputerName=Computer,AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress, ActionType="LogonFailure";
|
||||||
logonFail
|
logonFail
|
||||||
| union logonSuccess;
|
| union logonSuccess;
|
||||||
};
|
};
|
||||||
LogonEvents
|
LogonEvents
|
||||||
| where EventTime >= ago(30d)
|
| where EventTime >= ago(30d)
|
||||||
| where ActionType == "Logon"
|
| where ActionType == "Logon"
|
||||||
| summarize count() by ComputerName, AccountName
|
| summarize count() by ComputerName, AccountName
|
||||||
| where AccountName !startswith "Dnz" // DEMO - filter out a known account from baseline
|
| where AccountName !startswith "Dnz" // DEMO - filter out a known account from baseline
|
||||||
| join kind=leftouter
|
| join kind=leftouter
|
||||||
(
|
(
|
||||||
LogonEvents
|
LogonEvents
|
||||||
| where EventTime >= ago(1d)
|
| where EventTime >= ago(1d)
|
||||||
| where ActionType == "Logon"
|
| where ActionType == "Logon"
|
||||||
| summarize count() by ComputerName, AccountName
|
| summarize count() by ComputerName, AccountName
|
||||||
)
|
)
|
||||||
on ComputerName
|
on ComputerName
|
||||||
| where AccountName != AccountName1
|
| where AccountName != AccountName1
|
||||||
| summarize HostCount=dcount(ComputerName) by AccountName1
|
| summarize HostCount=dcount(ComputerName) by AccountName1
|
||||||
| render piechart
|
| 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'.
|
// 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
|
// Tags: #Initial Access #LateralMovement #Persistence
|
||||||
let top5 = SecurityEvent
|
let top5 = SecurityEvent
|
||||||
| where EventID == 4625 and AccountType == 'User'
|
| where EventID == 4625 and AccountType == 'User'
|
||||||
| extend Account_Name = extract(@"^(.*\\)?([^@]*)(@.*)?$", 2, tolower(Account))
|
| extend Account_Name = extract(@"^(.*\\)?([^@]*)(@.*)?$", 2, tolower(Account))
|
||||||
| summarize Attempts = count() by Account_Name
|
| summarize Attempts = count() by Account_Name
|
||||||
| where Account_Name != ""
|
| where Account_Name != ""
|
||||||
| top 5 by Attempts
|
| top 5 by Attempts
|
||||||
| summarize makelist(Account_Name);
|
| summarize makelist(Account_Name);
|
||||||
SecurityEvent
|
SecurityEvent
|
||||||
| where EventID == 4625 and AccountType == 'User'
|
| where EventID == 4625 and AccountType == 'User'
|
||||||
| extend Name = extract(@"^(.*\\)?([^@]*)(@.*)?$", 2, tolower(Account))
|
| extend Name = extract(@"^(.*\\)?([^@]*)(@.*)?$", 2, tolower(Account))
|
||||||
| extend Account_Name = iff(Name in (top5), Name, "Other")
|
| extend Account_Name = iff(Name in (top5), Name, "Other")
|
||||||
| where Account_Name != ""
|
| where Account_Name != ""
|
||||||
| summarize Attempts = count() by 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.
|
// 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.
|
// 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.
|
// IF no logon has succeeded - Order by number of attempts and unique accounts.
|
||||||
// Tags: #Initial Access #LateralMovement #Persistence
|
// Tags: #Initial Access #LateralMovement #Persistence
|
||||||
SecurityEvent
|
SecurityEvent
|
||||||
| where AccountType == "User"
|
| where AccountType == "User"
|
||||||
| where EventID in (4624, 4625)
|
| where EventID in (4624, 4625)
|
||||||
| summarize Unique_Accounts = dcount(Account), Attempts = count(), Succeeded=countif(EventID == 4624), Failed=countif(EventID == 4625) by IpAddress
|
| summarize Unique_Accounts = dcount(Account), Attempts = count(), Succeeded=countif(EventID == 4624), Failed=countif(EventID == 4625) by IpAddress
|
||||||
| where Failed > 0
|
| where Failed > 0
|
||||||
| order by Succeeded>0, todouble(Succeeded)/Attempts asc, Attempts desc
|
| order by Succeeded>0, todouble(Succeeded)/Attempts asc, Attempts desc
|
||||||
| project IP = IpAddress, Succeeded, Attempts, Unique_Accounts
|
| project IP = IpAddress, Succeeded, Attempts, Unique_Accounts
|
||||||
| take 10
|
| take 10
|
||||||
| order by Unique_Accounts desc
|
| order by Unique_Accounts desc
|
||||||
|
|
||||||
|
|
||||||
// Name: Summary of user logons by logon type
|
// 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.
|
// 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
|
// Tags: #Initial Access #LateralMovement #Persistence
|
||||||
SecurityEvent
|
SecurityEvent
|
||||||
| where EventID in (4624, 4625)
|
| where EventID in (4624, 4625)
|
||||||
| where AccountType == "User"
|
| where AccountType == "User"
|
||||||
| summarize Amount = count() by LogonTypeName
|
| summarize Amount = count() by LogonTypeName
|
||||||
|
|
||||||
|
|
||||||
// Name: Summary of failed user logons by reason of failure
|
// 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.
|
// 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
|
// Tags: #Initial Access #LateralMovement #Persistence
|
||||||
SecurityEvent
|
SecurityEvent
|
||||||
| where AccountType == 'User' and EventID == 4625
|
| where AccountType == 'User' and EventID == 4625
|
||||||
| extend Reason = case(
|
| extend Reason = case(
|
||||||
SubStatus == '0xc000005e', 'No logon servers available to service the logon request',
|
SubStatus == '0xc000005e', 'No logon servers available to service the logon request',
|
||||||
SubStatus == '0xc0000062', 'Account name is not properly formatted',
|
SubStatus == '0xc0000062', 'Account name is not properly formatted',
|
||||||
SubStatus == '0xc0000064', 'Account name does not exist',
|
SubStatus == '0xc0000064', 'Account name does not exist',
|
||||||
SubStatus == '0xc000006a', 'Incorrect password',
|
SubStatus == '0xc000006a', 'Incorrect password',
|
||||||
SubStatus == '0xc000006d', 'Bad user name or password',
|
SubStatus == '0xc000006d', 'Bad user name or password',
|
||||||
SubStatus == '0xc000006f', 'User logon blocked by account restriction',
|
SubStatus == '0xc000006f', 'User logon blocked by account restriction',
|
||||||
SubStatus == '0xc000006f', 'User logon outside of restricted logon hours',
|
SubStatus == '0xc000006f', 'User logon outside of restricted logon hours',
|
||||||
SubStatus == '0xc0000070', 'User logon blocked by workstation restriction',
|
SubStatus == '0xc0000070', 'User logon blocked by workstation restriction',
|
||||||
SubStatus == '0xc0000071', 'Password has expired',
|
SubStatus == '0xc0000071', 'Password has expired',
|
||||||
SubStatus == '0xc0000072', 'Account is disabled',
|
SubStatus == '0xc0000072', 'Account is disabled',
|
||||||
SubStatus == '0xc0000133', 'Clocks between DC and other computer too far out of sync',
|
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 == '0xc000015b', 'The user has not been granted the requested logon right at this machine',
|
||||||
SubStatus == '0xc0000193', 'Account has expirated',
|
SubStatus == '0xc0000193', 'Account has expirated',
|
||||||
SubStatus == '0xc0000224', 'User is required to change password at next logon',
|
SubStatus == '0xc0000224', 'User is required to change password at next logon',
|
||||||
SubStatus == '0xc0000234', 'Account is currently locked out',
|
SubStatus == '0xc0000234', 'Account is currently locked out',
|
||||||
strcat('Unknown reason substatus: ', SubStatus))
|
strcat('Unknown reason substatus: ', SubStatus))
|
||||||
| summarize count() by Reason
|
| summarize count() by Reason
|
||||||
|
|
||||||
|
|
||||||
// List of accounts locked out (event id 4740)
|
// List of accounts locked out (event id 4740)
|
||||||
// Tags: #Initial Access #LateralMovement #Persistence
|
// Tags: #Initial Access #LateralMovement #Persistence
|
||||||
SecurityEvent
|
SecurityEvent
|
||||||
| where EventID == 4740
|
| where EventID == 4740
|
||||||
|
|
||||||
|
|
||||||
// Attackers often move to the next step which can loosely be called network propagation stage.
|
// 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.
|
// 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.
|
// 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
|
// Tags: #Initial Access #LateralMovement #Persistence
|
||||||
SecurityEvent
|
SecurityEvent
|
||||||
| where EventID == 4624
|
| where EventID == 4624
|
||||||
| where AccountType == "User"
|
| where AccountType == "User"
|
||||||
| where TimeGenerated >= ago(1d)
|
| where TimeGenerated >= ago(1d)
|
||||||
| summarize IndividualAccounts = dcount(Account) by Computer
|
| summarize IndividualAccounts = dcount(Account) by Computer
|
||||||
| where IndividualAccounts > 4
|
| where IndividualAccounts > 4
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
//Shows authentication volume by user agent and IP address.
|
//Shows authentication volume by user agent and IP address.
|
||||||
//Tracking via user agent is one way to differentiate between types of connecting device.
|
//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 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.
|
//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.
|
//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)
|
// Office - authentications by UA & IP (likely only manageable for small tenants)
|
||||||
// Tags: #Discovery #LateralMovement #Collection
|
// Tags: #Discovery #LateralMovement #Collection
|
||||||
OfficeActivity
|
OfficeActivity
|
||||||
| where RecordType in ("AzureActiveDirectoryAccountLogon", "AzureActiveDirectoryStsLogon")
|
| where RecordType in ("AzureActiveDirectoryAccountLogon", "AzureActiveDirectoryStsLogon")
|
||||||
| where Operation startswith "UserLoggedIn"
|
| where Operation startswith "UserLoggedIn"
|
||||||
| extend UserAgent = extractjson("$[0].Value", ExtendedProperties, typeof(string))
|
| extend UserAgent = extractjson("$[0].Value", ExtendedProperties, typeof(string))
|
||||||
| project Operation, UserId, TimeGenerated , UserAgent, ClientIP
|
| project Operation, UserId, TimeGenerated , UserAgent, ClientIP
|
||||||
| summarize userAgentCount=count() by UserAgent, ClientIP
|
| summarize userAgentCount=count() by UserAgent, ClientIP
|
||||||
| sort by userAgentCount desc;
|
| sort by userAgentCount desc;
|
||||||
|
|
||||||
//Shows authentication volume by user agent.
|
//Shows authentication volume by user agent.
|
||||||
//Tracking via user agent is one way to differentiate between types of connecting device.
|
//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 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.
|
//Examining authentications by new devices is a potential avenue to discover unauthorized access.
|
||||||
// Tags: #Discovery #LateralMovement #Collection
|
// Tags: #Discovery #LateralMovement #Collection
|
||||||
OfficeActivity
|
OfficeActivity
|
||||||
| where RecordType in ("AzureActiveDirectoryAccountLogon", "AzureActiveDirectoryStsLogon")
|
| where RecordType in ("AzureActiveDirectoryAccountLogon", "AzureActiveDirectoryStsLogon")
|
||||||
| where Operation startswith "UserLoggedIn"
|
| where Operation startswith "UserLoggedIn"
|
||||||
| extend UserAgent = extractjson("$[0].Value", ExtendedProperties, typeof(string))
|
| extend UserAgent = extractjson("$[0].Value", ExtendedProperties, typeof(string))
|
||||||
| extend machineIndex=indexof(UserAgent, "machine_id")
|
| extend machineIndex=indexof(UserAgent, "machine_id")
|
||||||
| extend UserAgent = substring(UserAgent, 0, machineIndex)
|
| extend UserAgent = substring(UserAgent, 0, machineIndex)
|
||||||
| project Operation, UserId, TimeGenerated , UserAgent
|
| project Operation, UserId, TimeGenerated , UserAgent
|
||||||
| summarize userAgentCount=count() by UserAgent
|
| summarize userAgentCount=count() by UserAgent
|
||||||
| sort by userAgentCount desc;
|
| 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.
|
// 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:
|
// 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
|
// 1- UserAgents seen in authentications from multiple IPs within short timeframe
|
||||||
// 2- User Ids seen authenticated from multiple IPs
|
// 2- User Ids seen authenticated from multiple IPs
|
||||||
// The time window join looks for instances of a small elpased time between logons.
|
// 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 timeRange=ago(7d);
|
||||||
let officeAuthentications =
|
let officeAuthentications =
|
||||||
OfficeActivity
|
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
|
// Name: cscript script daily summary breakdown
|
||||||
// Tags: #Execution
|
//
|
||||||
|
// Description: breakdown of scripts running in the environment
|
||||||
|
//
|
||||||
|
// Data source: SecurityEvent
|
||||||
|
//
|
||||||
|
// Techniques: #Execution
|
||||||
|
//
|
||||||
let ProcessCreationEvents=() {
|
let ProcessCreationEvents=() {
|
||||||
let processEvents=SecurityEvent
|
let processEvents=SecurityEvent
|
||||||
| where EventID==4688
|
| where EventID==4688
|
|
@ -1,17 +1,23 @@
|
||||||
// The query finds attempts to list users or groups using Net commands
|
// Name: Enumeration of users and groups
|
||||||
// Tags: #Initial Access #Execution #Persistence #Lateral Movement #Discovery
|
|
||||||
let ProcessCreationEvents=() {
|
// Description: finds attempts to list users or groups using the built-in Windows 'net' tool
|
||||||
let processEvents=SecurityEvent
|
|
||||||
| where EventID==4688
|
// Data source: SecurityEvent
|
||||||
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
|
|
||||||
FileName=tostring(split(NewProcessName, '\\')[-1]),
|
// Techniques: #Discovery
|
||||||
ProcessCommandLine = CommandLine,
|
|
||||||
FolderPath = "",
|
let ProcessCreationEvents=() {
|
||||||
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
|
let processEvents=SecurityEvent
|
||||||
processEvents};
|
| where EventID==4688
|
||||||
ProcessCreationEvents
|
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
|
||||||
| where FileName == 'net.exe' and AccountName != "" and ProcessCommandLine !contains '\\' and ProcessCommandLine !contains '/add'
|
FileName=tostring(split(NewProcessName, '\\')[-1]),
|
||||||
| where (ProcessCommandLine contains ' user ' or ProcessCommandLine contains ' group ') and (ProcessCommandLine endswith ' /do' or ProcessCommandLine endswith ' /domain')
|
ProcessCommandLine = CommandLine,
|
||||||
| extend Target = extract("(?i)[user|group] (\"*[a-zA-Z0-9-_ ]+\"*)", 1, ProcessCommandLine) | filter Target != ''
|
FolderPath = "",
|
||||||
| project AccountName, Target, ProcessCommandLine, ComputerName, TimeGenerated
|
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
|
| 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
|
// 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.
|
// Description: Summarizes uses of uncommon & undocumented commandline switches to create persistence
|
||||||
// Read more here: https://attack.mitre.org/wiki/Technique/T1136
|
// User accounts may be created to achieve persistence on a machine.
|
||||||
// Query for users being created using "net user" command
|
// Read more here: https://attack.mitre.org/wiki/Technique/T1136
|
||||||
// "net user" commands are noisy, so needs to be joined with another signal -
|
// Query for users being created using "net user" command
|
||||||
// e.g. in this example we look (e.g. /ad instead of /add)
|
// "net user" commands are noisy, so needs to be joined with another signal -
|
||||||
// Tags: #InitialAccess #Execution #LateralMovement #Persistance #DefenseEvasion
|
// e.g. in this example we look for some undocumented variations (e.g. /ad instead of /add)
|
||||||
SecurityEvent
|
//
|
||||||
| where EventID==4688
|
// Data source: SecurityEvent
|
||||||
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName,
|
//
|
||||||
AccountDomain=SubjectDomainName, FileName=tostring(split(NewProcessName, '\\')[-1]),
|
// Techniques: #Persistence
|
||||||
ProcessCommandLine = CommandLine,
|
//
|
||||||
FolderPath = "", InitiatingProcessFileName=ParentProcessName,
|
SecurityEvent
|
||||||
InitiatingProcessCommandLine="",InitiatingProcessParentFileName=""
|
| where EventID==4688
|
||||||
| where FileName in~ ("net.exe", "net1.exe")
|
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName,
|
||||||
| parse kind=regex flags=iU ProcessCommandLine with * "user " CreatedUser " " * "/ad"
|
AccountDomain=SubjectDomainName, FileName=tostring(split(NewProcessName, '\\')[-1]),
|
||||||
| where not(FileName =~ "net1.exe" and InitiatingProcessFileName =~ "net.exe" and replace("net", "net1", InitiatingProcessCommandLine) =~ ProcessCommandLine)
|
ProcessCommandLine = CommandLine,
|
||||||
| extend CreatedOnLocalMachine=(ProcessCommandLine !contains "/do")
|
FolderPath = "", InitiatingProcessFileName=ParentProcessName,
|
||||||
| where ProcessCommandLine contains "/add" or (CreatedOnLocalMachine == 0 and ProcessCommandLine !contains "/domain")
|
InitiatingProcessCommandLine="",InitiatingProcessParentFileName=""
|
||||||
| summarize MachineCount=dcount(ComputerName) by CreatedUser, CreatedOnLocalMachine, InitiatingProcessFileName, FileName, ProcessCommandLine, InitiatingProcessCommandLine
|
| 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.
|
// Name: powershell downloads
|
||||||
// Tags: #Initial Access, #Execution, #Persistence
|
//
|
||||||
let ProcessCreationEvents=() {
|
// Description: Finds PowerShell execution events that could involve a download
|
||||||
let processEvents=SecurityEvent
|
//
|
||||||
| where EventID==4688
|
// Data source: SecurityEvent
|
||||||
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
|
//
|
||||||
FileName=tostring(split(NewProcessName, '\\')[-1]),
|
// Techniques: #Initial Access, #Execution, #Persistence
|
||||||
ProcessCommandLine = CommandLine,
|
//
|
||||||
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
|
let ProcessCreationEvents=() {
|
||||||
processEvents};
|
let processEvents=SecurityEvent
|
||||||
ProcessCreationEvents
|
| where EventID==4688
|
||||||
| where FileName in~ ("powershell.exe", "powershell_ise.exe")
|
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
|
||||||
| where ProcessCommandLine has "Net.WebClient"
|
FileName=tostring(split(NewProcessName, '\\')[-1]),
|
||||||
or ProcessCommandLine has "DownloadFile"
|
ProcessCommandLine = CommandLine,
|
||||||
or ProcessCommandLine has "Invoke-WebRequest"
|
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
|
||||||
or ProcessCommandLine has "Invoke-Shellcode"
|
processEvents};
|
||||||
or ProcessCommandLine contains "http:"
|
ProcessCreationEvents
|
||||||
| project TimeGenerated, ComputerName, InitiatingProcessFileName, FileName, ProcessCommandLine
|
| 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
|
| top 100 by TimeGenerated
|
|
@ -1,9 +1,15 @@
|
||||||
// Identify and decode new encoded powershell scripts this week versus previous fortnight - generic
|
// Name: new powershell scripts encoded on the commandline
|
||||||
// Tags: #Initial Access, #Execution, #Persistence
|
//
|
||||||
|
// Description: Identify and decode new encoded powershell scripts this week versus previous fortnight
|
||||||
|
//
|
||||||
|
// Data source: SecurityEvent
|
||||||
|
//
|
||||||
|
// Techniques: #Initial Access, #Execution, #Persistence
|
||||||
|
//
|
||||||
let ProcessCreationEvents=() {
|
let ProcessCreationEvents=() {
|
||||||
let processEvents=SecurityEvent
|
let processEvents=SecurityEvent
|
||||||
| where EventID==4688
|
| where EventID==4688
|
||||||
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
|
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName,AccountDomain=SubjectDomainName,
|
||||||
FileName=tostring(split(NewProcessName, '\\')[-1]),
|
FileName=tostring(split(NewProcessName, '\\')[-1]),
|
||||||
ProcessCommandLine = CommandLine,
|
ProcessCommandLine = CommandLine,
|
||||||
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
|
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!)
|
// Name: uncommon processes - bottom 5%
|
||||||
// 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.
|
// Description: Identify and decode new encoded powershell scripts this week versus previous fortnight
|
||||||
// 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%
|
// Description:
|
||||||
// Tags: #Initial Access, #Execution, #Persistence, #Privilege Escalation, #Credential Access, #Discovery, #Lateral Movement, #Collection, #Exfiltration, #Command and Control
|
// Shows the rarest processes seen running for the first time. (Performs best over longer time ranges - eg 3+ days rather than 24 hours!)
|
||||||
let ProcessCreationEvents=() {
|
// These new processes could be benign new programs installed on hosts;
|
||||||
let processEvents=SecurityEvent
|
// However, especially in normally stable environments, these new processes could provide an indication of an unauthorized/malicious binary that has been installed and run.
|
||||||
| where EventID==4688
|
// Reviewing the wider context of the logon sessions in which these binaries ran can provide a good starting point for identifying possible attacks.
|
||||||
// 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")
|
// Data source: SecurityEvent
|
||||||
| 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")
|
// Techniques: #Initial Access, #Execution, #Persistence, #Privilege Escalation, #Credential Access, #Discovery, #Lateral Movement, #Collection, #Exfiltration, #Command and Control
|
||||||
| where not(NewProcessName matches regex @"Installer\\MSI[0-9A-Fa-f]{4}\.tmp")
|
//
|
||||||
| project TimeGenerated,
|
let ProcessCreationEvents=() {
|
||||||
ComputerName=Computer,
|
let processEvents=SecurityEvent
|
||||||
AccountName=SubjectUserName,
|
| where EventID==4688
|
||||||
AccountDomain=SubjectDomainName,
|
// filter out common randomly named files related to MSI installers and browsers
|
||||||
FileName=tostring(split(NewProcessName, '\\')[-1]),
|
| where not(NewProcessName matches regex @"Temp\\[0-9]{1}\\TRA[0-9A-Fa-f]{3}\.tmp")
|
||||||
ProcessCommandLine = CommandLine,
|
| where not(NewProcessName matches regex @"Temp\\[0-9]{1}\\TRA[0-9A-Fa-f]{4}\.tmp")
|
||||||
InitiatingProcessFileName=ParentProcessName,
|
| where not(NewProcessName matches regex @"Installer\\MSI[0-9A-Fa-f]{3}\.tmp")
|
||||||
InitiatingProcessCommandLine="",
|
| where not(NewProcessName matches regex @"Installer\\MSI[0-9A-Fa-f]{4}\.tmp")
|
||||||
InitiatingProcessParentFileName="";
|
| project TimeGenerated,
|
||||||
processEvents;
|
ComputerName=Computer,
|
||||||
};
|
AccountName=SubjectUserName,
|
||||||
let normalizedProcesses = ProcessCreationEvents
|
AccountDomain=SubjectDomainName,
|
||||||
| 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
|
FileName=tostring(split(NewProcessName, '\\')[-1]),
|
||||||
| project TimeGenerated, FileName=replace(@'\d', 'n', FileName); // normalize digits away
|
ProcessCommandLine = CommandLine,
|
||||||
let freqs = normalizedProcesses
|
InitiatingProcessFileName=ParentProcessName,
|
||||||
| summarize frequency=count() by FileName
|
InitiatingProcessCommandLine="",
|
||||||
| join kind= leftouter (
|
InitiatingProcessParentFileName="";
|
||||||
normalizedProcesses
|
processEvents;
|
||||||
| summarize Since=min(TimeGenerated), LastSeen=max(TimeGenerated) by FileName
|
};
|
||||||
) on FileName;
|
let normalizedProcesses = ProcessCreationEvents
|
||||||
freqs
|
| 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
|
||||||
| where frequency <= toscalar( freqs | serialize | project frequency | summarize percentiles(frequency, 5))
|
| project TimeGenerated, FileName=replace(@'\d', 'n', FileName); // normalize digits away
|
||||||
| order by frequency asc
|
let freqs = normalizedProcesses
|
||||||
| project FileName, frequency, Since, LastSeen
|
| summarize frequency=count() by FileName
|
||||||
// restrict results to unusual processes seen in last day
|
| 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)
|
| 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
|
// 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
|
// an unusually high ratio of distinct geolocations versus total number of authentications
|
||||||
// Tags: #InitialAccess
|
//
|
||||||
|
// Data source: SigninLogs
|
||||||
|
//
|
||||||
|
// Techniques: #InitialAccess
|
||||||
|
//
|
||||||
let timeRange=ago(14d);
|
let timeRange=ago(14d);
|
||||||
let azureSignIns =
|
let azureSignIns =
|
||||||
SigninLogs
|
SigninLogs
|
|
@ -1,8 +1,12 @@
|
||||||
// Name: azure AD signins from new locations.
|
// Name: Azure Active Directory 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
|
// Description: New Azure Active Directory signin locations today versus historical Azure Active Directory signin data
|
||||||
// one might see authentication attempts for many accounts from a new location.
|
// In the case of password spraying or brute force attacks one might see authentication attempts for many accounts from a new location.
|
||||||
// Tags: #InitialAccess
|
//
|
||||||
|
// Data source: SigninLogs
|
||||||
|
//
|
||||||
|
// Techniques: #InitialAccess
|
||||||
|
//
|
||||||
SigninLogs
|
SigninLogs
|
||||||
| where TimeGenerated >= ago(1d)
|
| where TimeGenerated >= ago(1d)
|
||||||
| summarize perIdentityAuthCount=count() by Identity, locationString= strcat(tostring(LocationDetails["countryOrRegion"]), "/", tostring(LocationDetails["state"]), "/", tostring(LocationDetails["city"]), ";" , tostring(LocationDetails["geoCoordinates"]))
|
| 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
|
// Name: Azure Active Directory sign-in 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
|
// Description: This query over Azure Active Directory sign-in activity highlights accounts associated
|
||||||
// Tags: #InitialAccess
|
// with multiple authentications from different geographical locations in a short space of time.
|
||||||
|
//
|
||||||
|
// Data source: SigninLogs
|
||||||
|
//
|
||||||
|
// Techniques: #InitialAccess
|
||||||
|
//
|
||||||
let timeRange=ago(10d);
|
let timeRange=ago(10d);
|
||||||
let signIns = SigninLogs
|
let signIns = SigninLogs
|
||||||
| where TimeGenerated >= timeRange
|
| 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
|
|
Загрузка…
Ссылка в новой задаче