Updating entities and putting in YAML format
This commit is contained in:
Родитель
2f8bbb1e7f
Коммит
0b92a4bf6a
|
@ -1,80 +0,0 @@
|
|||
// Name: VIP account more than 6 failed logons in 10
|
||||
// Description: VIP Account with more than 6 failed logon attempts in 10 minutes, include your own VIP list in the table below
|
||||
// NTSTATUS codes - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
|
||||
//
|
||||
// Id: 892cd37e-f9e1-49c3-b0b2-d74f52ac7b71
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #Discovery, #LateralMovement
|
||||
//
|
||||
// Create DataTable with your own values, example below shows dummy usernames and domain
|
||||
let List = datatable(VIPUser:string, Domain:string)["Bob", "Domain", "joe", "domain", "MATT", "DOMAIN", "administrator", ""];
|
||||
let timeframe = 10m;
|
||||
List
|
||||
| project TargetUserName = tolower(VIPUser), TargetDomainName = toupper(Domain)
|
||||
| join kind= rightsemi (
|
||||
SecurityEvent
|
||||
| where TimeGenerated > ago(2*timeframe)
|
||||
| where EventID == "4625"
|
||||
| where AccountType == "User"
|
||||
) on TargetUserName, TargetDomainName
|
||||
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), FailedVIPLogons = count() by EventID, Activity, WorkstationName, Account, TargetAccount, TargetUserName, TargetDomainName, LogonType, LogonTypeName, LogonProcessName, Status, SubStatus
|
||||
| where FailedVIPLogons >= 6
|
||||
// map the most common ntstatus codes
|
||||
| extend StatusDesc = case(
|
||||
Status =~ "0x80090302", "SEC_E_UNSUPPORTED_FUNCTION",
|
||||
Status =~ "0x80090308", "SEC_E_INVALID_TOKEN",
|
||||
Status =~ "0x8009030E", "SEC_E_NO_CREDENTIALS",
|
||||
Status =~ "0xC0000008", "STATUS_INVALID_HANDLE",
|
||||
Status =~ "0xC0000017", "STATUS_NO_MEMORY",
|
||||
Status =~ "0xC0000022", "STATUS_ACCESS_DENIED",
|
||||
Status =~ "0xC0000034", "STATUS_OBJECT_NAME_NOT_FOUND",
|
||||
Status =~ "0xC000005E", "STATUS_NO_LOGON_SERVERS",
|
||||
Status =~ "0xC000006A", "STATUS_WRONG_PASSWORD",
|
||||
Status =~ "0xC000006D", "STATUS_LOGON_FAILURE",
|
||||
Status =~ "0xC000006E", "STATUS_ACCOUNT_RESTRICTION",
|
||||
Status =~ "0xC0000073", "STATUS_NONE_MAPPED",
|
||||
Status =~ "0xC00000FE", "STATUS_NO_SUCH_PACKAGE",
|
||||
Status =~ "0xC000009A", "STATUS_INSUFFICIENT_RESOURCES",
|
||||
Status =~ "0xC00000DC", "STATUS_INVALID_SERVER_STATE",
|
||||
Status =~ "0xC0000106", "STATUS_NAME_TOO_LONG",
|
||||
Status =~ "0xC000010B", "STATUS_INVALID_LOGON_TYPE",
|
||||
Status =~ "0xC000015B", "STATUS_LOGON_TYPE_NOT_GRANTED",
|
||||
Status =~ "0xC000018B", "STATUS_NO_TRUST_SAM_ACCOUNT",
|
||||
Status =~ "0xC0000224", "STATUS_PASSWORD_MUST_CHANGE",
|
||||
Status =~ "0xC0000234", "STATUS_ACCOUNT_LOCKED_OUT",
|
||||
Status =~ "0xC00002EE", "STATUS_UNFINISHED_CONTEXT_DELETED",
|
||||
"See - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55"
|
||||
)
|
||||
| extend SubStatusDesc = case(
|
||||
SubStatus =~ "0x80090325", "SEC_E_UNTRUSTED_ROOT",
|
||||
SubStatus =~ "0xC0000008", "STATUS_INVALID_HANDLE",
|
||||
SubStatus =~ "0xC0000022", "STATUS_ACCESS_DENIED",
|
||||
SubStatus =~ "0xC0000064", "STATUS_NO_SUCH_USER",
|
||||
SubStatus =~ "0xC000006A", "STATUS_WRONG_PASSWORD",
|
||||
SubStatus =~ "0xC000006D", "STATUS_LOGON_FAILURE",
|
||||
SubStatus =~ "0xC000006E", "STATUS_ACCOUNT_RESTRICTION",
|
||||
SubStatus =~ "0xC000006F", "STATUS_INVALID_LOGON_HOURS",
|
||||
SubStatus =~ "0xC0000070", "STATUS_INVALID_WORKSTATION",
|
||||
SubStatus =~ "0xC0000071", "STATUS_PASSWORD_EXPIRED",
|
||||
SubStatus =~ "0xC0000072", "STATUS_ACCOUNT_DISABLED",
|
||||
SubStatus =~ "0xC0000073", "STATUS_NONE_MAPPED",
|
||||
SubStatus =~ "0xC00000DC", "STATUS_INVALID_SERVER_STATE",
|
||||
SubStatus =~ "0xC0000133", "STATUS_TIME_DIFFERENCE_AT_DC",
|
||||
SubStatus =~ "0xC000018D", "STATUS_TRUSTED_RELATIONSHIP_FAILURE",
|
||||
SubStatus =~ "0xC0000193", "STATUS_ACCOUNT_EXPIRED",
|
||||
SubStatus =~ "0xC0000380", "STATUS_SMARTCARD_WRONG_PIN",
|
||||
SubStatus =~ "0xC0000381", "STATUS_SMARTCARD_CARD_BLOCKED",
|
||||
SubStatus =~ "0xC0000382", "STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED",
|
||||
SubStatus =~ "0xC0000383", "STATUS_SMARTCARD_NO_CARD",
|
||||
SubStatus =~ "0xC0000384", "STATUS_SMARTCARD_NO_KEY_CONTAINER",
|
||||
SubStatus =~ "0xC0000385", "STATUS_SMARTCARD_NO_CERTIFICATE",
|
||||
SubStatus =~ "0xC0000386", "STATUS_SMARTCARD_NO_KEYSET",
|
||||
SubStatus =~ "0xC0000387", "STATUS_SMARTCARD_IO_ERROR",
|
||||
SubStatus =~ "0xC0000388", "STATUS_DOWNGRADE_DETECTED",
|
||||
SubStatus =~ "0xC0000389", "STATUS_SMARTCARD_CERT_REVOKED",
|
||||
"See - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55"
|
||||
)
|
||||
| project StartTimeUtc, EndTimeUtc, FailedVIPLogons, EventID, Activity, WorkstationName, Account, TargetAccount, TargetUserName, TargetDomainName, LogonType, LogonTypeName, LogonProcessName, Status, StatusDesc, SubStatus, SubStatusDesc
|
||||
| extend AccountCustomEntity = Account
|
|
@ -0,0 +1,83 @@
|
|||
id: 892cd37e-f9e1-49c3-b0b2-d74f52ac7b71
|
||||
name: VIP account more than 6 failed logons in 10
|
||||
description: |
|
||||
'VIP Account with more than 6 failed logon attempts in 10 minutes, include your own VIP list in the table below
|
||||
NTSTATUS codes - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- CredentialAccess
|
||||
query: |
|
||||
|
||||
// Create DataTable with your own values, example below shows dummy usernames and domain
|
||||
let List = datatable(VIPUser:string, Domain:string)["Bob", "Domain", "joe", "domain", "MATT", "DOMAIN", "administrator", ""];
|
||||
let timeframe = 10m;
|
||||
List
|
||||
| project TargetUserName = tolower(VIPUser), TargetDomainName = toupper(Domain)
|
||||
| join kind= rightsemi (
|
||||
SecurityEvent
|
||||
| where TimeGenerated > ago(2*timeframe)
|
||||
| where EventID == "4625"
|
||||
| where AccountType == "User"
|
||||
) on TargetUserName, TargetDomainName
|
||||
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), FailedVIPLogons = count() by EventID, Activity, WorkstationName, Account, TargetAccount, TargetUserName, TargetDomainName, LogonType, LogonTypeName, LogonProcessName, Status, SubStatus
|
||||
| where FailedVIPLogons >= 6
|
||||
// map the most common ntstatus codes
|
||||
| extend StatusDesc = case(
|
||||
Status =~ "0x80090302", "SEC_E_UNSUPPORTED_FUNCTION",
|
||||
Status =~ "0x80090308", "SEC_E_INVALID_TOKEN",
|
||||
Status =~ "0x8009030E", "SEC_E_NO_CREDENTIALS",
|
||||
Status =~ "0xC0000008", "STATUS_INVALID_HANDLE",
|
||||
Status =~ "0xC0000017", "STATUS_NO_MEMORY",
|
||||
Status =~ "0xC0000022", "STATUS_ACCESS_DENIED",
|
||||
Status =~ "0xC0000034", "STATUS_OBJECT_NAME_NOT_FOUND",
|
||||
Status =~ "0xC000005E", "STATUS_NO_LOGON_SERVERS",
|
||||
Status =~ "0xC000006A", "STATUS_WRONG_PASSWORD",
|
||||
Status =~ "0xC000006D", "STATUS_LOGON_FAILURE",
|
||||
Status =~ "0xC000006E", "STATUS_ACCOUNT_RESTRICTION",
|
||||
Status =~ "0xC0000073", "STATUS_NONE_MAPPED",
|
||||
Status =~ "0xC00000FE", "STATUS_NO_SUCH_PACKAGE",
|
||||
Status =~ "0xC000009A", "STATUS_INSUFFICIENT_RESOURCES",
|
||||
Status =~ "0xC00000DC", "STATUS_INVALID_SERVER_STATE",
|
||||
Status =~ "0xC0000106", "STATUS_NAME_TOO_LONG",
|
||||
Status =~ "0xC000010B", "STATUS_INVALID_LOGON_TYPE",
|
||||
Status =~ "0xC000015B", "STATUS_LOGON_TYPE_NOT_GRANTED",
|
||||
Status =~ "0xC000018B", "STATUS_NO_TRUST_SAM_ACCOUNT",
|
||||
Status =~ "0xC0000224", "STATUS_PASSWORD_MUST_CHANGE",
|
||||
Status =~ "0xC0000234", "STATUS_ACCOUNT_LOCKED_OUT",
|
||||
Status =~ "0xC00002EE", "STATUS_UNFINISHED_CONTEXT_DELETED",
|
||||
"See - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55"
|
||||
)
|
||||
| extend SubStatusDesc = case(
|
||||
SubStatus =~ "0x80090325", "SEC_E_UNTRUSTED_ROOT",
|
||||
SubStatus =~ "0xC0000008", "STATUS_INVALID_HANDLE",
|
||||
SubStatus =~ "0xC0000022", "STATUS_ACCESS_DENIED",
|
||||
SubStatus =~ "0xC0000064", "STATUS_NO_SUCH_USER",
|
||||
SubStatus =~ "0xC000006A", "STATUS_WRONG_PASSWORD",
|
||||
SubStatus =~ "0xC000006D", "STATUS_LOGON_FAILURE",
|
||||
SubStatus =~ "0xC000006E", "STATUS_ACCOUNT_RESTRICTION",
|
||||
SubStatus =~ "0xC000006F", "STATUS_INVALID_LOGON_HOURS",
|
||||
SubStatus =~ "0xC0000070", "STATUS_INVALID_WORKSTATION",
|
||||
SubStatus =~ "0xC0000071", "STATUS_PASSWORD_EXPIRED",
|
||||
SubStatus =~ "0xC0000072", "STATUS_ACCOUNT_DISABLED",
|
||||
SubStatus =~ "0xC0000073", "STATUS_NONE_MAPPED",
|
||||
SubStatus =~ "0xC00000DC", "STATUS_INVALID_SERVER_STATE",
|
||||
SubStatus =~ "0xC0000133", "STATUS_TIME_DIFFERENCE_AT_DC",
|
||||
SubStatus =~ "0xC000018D", "STATUS_TRUSTED_RELATIONSHIP_FAILURE",
|
||||
SubStatus =~ "0xC0000193", "STATUS_ACCOUNT_EXPIRED",
|
||||
SubStatus =~ "0xC0000380", "STATUS_SMARTCARD_WRONG_PIN",
|
||||
SubStatus =~ "0xC0000381", "STATUS_SMARTCARD_CARD_BLOCKED",
|
||||
SubStatus =~ "0xC0000382", "STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED",
|
||||
SubStatus =~ "0xC0000383", "STATUS_SMARTCARD_NO_CARD",
|
||||
SubStatus =~ "0xC0000384", "STATUS_SMARTCARD_NO_KEY_CONTAINER",
|
||||
SubStatus =~ "0xC0000385", "STATUS_SMARTCARD_NO_CERTIFICATE",
|
||||
SubStatus =~ "0xC0000386", "STATUS_SMARTCARD_NO_KEYSET",
|
||||
SubStatus =~ "0xC0000387", "STATUS_SMARTCARD_IO_ERROR",
|
||||
SubStatus =~ "0xC0000388", "STATUS_DOWNGRADE_DETECTED",
|
||||
SubStatus =~ "0xC0000389", "STATUS_SMARTCARD_CERT_REVOKED",
|
||||
"See - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55"
|
||||
)
|
||||
| project StartTimeUtc, EndTimeUtc, FailedVIPLogons, EventID, Activity, WorkstationName, Account, TargetAccount, TargetUserName, TargetDomainName, LogonType, LogonTypeName, LogonProcessName, Status, StatusDesc, SubStatus, SubStatusDesc
|
||||
| extend timestamp = StartTimeUtc, AccountCustomEntity = Account
|
|
@ -1,26 +0,0 @@
|
|||
// 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
|
||||
//
|
||||
// Id: e7642e6e-cf27-46ec-a4b9-e4475228fead
|
||||
//
|
||||
// Tactics: #InitialAccess, #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
|
|
@ -0,0 +1,38 @@
|
|||
id: e7642e6e-cf27-46ec-a4b9-e4475228fead
|
||||
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'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- CredentialAccess
|
||||
- LateralMovement
|
||||
relevantTechniques:
|
||||
- T1110
|
||||
query: |
|
||||
|
||||
let timeframe = 1d;
|
||||
SecurityEvent
|
||||
| where TimeGenerated >= ago(timeframe)
|
||||
| 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 StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), count() by Reason
|
||||
| extend timestamp = StartTimeUtc
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
// Name: Group added to Built in Domain Local or Global Group
|
||||
// Description: A Group created in the last 7 days was added to a privileged built in domain local group or global group such as the Enterprise Admins, Cert Publishers or DnsAdmins
|
||||
// Be sure to verify this is an expected addition
|
||||
//
|
||||
// Id: cb47a115-2616-4d56-890d-b28c14bc83e4
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #Persistence, #Discovery, #LateralMovement, #Collection, #PrivilegeEscalation
|
||||
//
|
||||
let timeframe = 7d;
|
||||
// For AD SID mappings - https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/active-directory-security-groups
|
||||
let WellKnownLocalSID = "S-1-5-32-5[0-9][0-9]";
|
||||
let WellKnownGroupSID = "S-1-5-21-[0-9]*-[0-9]*-[0-9]*-5[0-9][0-9]|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1102|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1103";
|
||||
let GroupAddition = SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
// 4728 - A member was added to a security-enabled global group
|
||||
// 4732 - A member was added to a security-enabled local group
|
||||
// 4756 - A member was added to a security-enabled universal group
|
||||
| where EventID in ("4728", "4732", "4756")
|
||||
| where AccountType == "User" and MemberName == "-"
|
||||
// Exclude Remote Desktop Users group: S-1-5-32-555
|
||||
| where TargetSid !in ("S-1-5-32-555")
|
||||
| where TargetSid matches regex WellKnownLocalSID or TargetSid matches regex WellKnownGroupSID
|
||||
| project GroupAddTime = TimeGenerated, GroupAddEventID = EventID, GroupAddActivity = Activity, GroupAddComputer = Computer, GroupAddTargetUserName = TargetUserName, GroupAddTargetDomainName = TargetDomainName, GroupAddTargetSid = TargetSid, GroupAddSubjectUserName = SubjectUserName, GroupAddSubjectUserSid = SubjectUserSid, GroupSid = MemberSid, Account, Computer
|
||||
| extend AccountCustomEntity = Account, HostCustomEntity = Computer;
|
||||
let GroupCreated = SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
// 4727 - A security-enabled global group was created
|
||||
// 4731 - A security-enabled local group was created
|
||||
// 4754 - A security-enabled universal group was created
|
||||
| where EventID in ("4727", "4731", "4754")
|
||||
| where AccountType == "User"
|
||||
| project GroupCreateTime = TimeGenerated, GroupCreateEventID = EventID, GroupCreateActivity = Activity, GroupCreateComputer = Computer, GroupCreateTargetUserName = TargetUserName, GroupCreateTargetDomainName = TargetDomainName, GroupCreateSubjectUserName = SubjectUserName, GroupCreateSubjectDomainName = SubjectDomainName, GroupCreateSubjectUserSid = SubjectUserSid, GroupSid = TargetSid, Account, Computer
|
||||
| extend AccountCustomEntity = Account, HostCustomEntity = Computer;
|
||||
GroupCreated
|
||||
| join (
|
||||
GroupAddition
|
||||
) on GroupSid
|
|
@ -0,0 +1,51 @@
|
|||
id: cb47a115-2616-4d56-890d-b28c14bc83e4
|
||||
name: Group added to Built in Domain Local or Global Group
|
||||
description: |
|
||||
'A Group created in the last 7 days was added to a privileged built in domain local group or global group such as the
|
||||
Enterprise Admins, Cert Publishers or DnsAdmins. Be sure to verify this is an expected addition'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Persistence
|
||||
- PrivilegeEscalation
|
||||
relevantTechniques:
|
||||
- T1098
|
||||
- T1078
|
||||
query: |
|
||||
|
||||
let timeframe = 7d;
|
||||
// For AD SID mappings - https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/active-directory-security-groups
|
||||
let WellKnownLocalSID = "S-1-5-32-5[0-9][0-9]";
|
||||
let WellKnownGroupSID = "S-1-5-21-[0-9]*-[0-9]*-[0-9]*-5[0-9][0-9]|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1102|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1103";
|
||||
let GroupAddition = SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
// 4728 - A member was added to a security-enabled global group
|
||||
// 4732 - A member was added to a security-enabled local group
|
||||
// 4756 - A member was added to a security-enabled universal group
|
||||
| where EventID in ("4728", "4732", "4756")
|
||||
| where AccountType == "User" and MemberName == "-"
|
||||
// Exclude Remote Desktop Users group: S-1-5-32-555
|
||||
| where TargetSid !in ("S-1-5-32-555")
|
||||
| where TargetSid matches regex WellKnownLocalSID or TargetSid matches regex WellKnownGroupSID
|
||||
| project GroupAddTime = TimeGenerated, GroupAddEventID = EventID, GroupAddActivity = Activity, GroupAddComputer = Computer,
|
||||
GroupAddTargetUserName = TargetUserName, GroupAddTargetDomainName = TargetDomainName, GroupAddTargetSid = TargetSid,
|
||||
GroupAddSubjectUserName = SubjectUserName, GroupAddSubjectUserSid = SubjectUserSid, GroupSid = MemberSid, Account, Computer
|
||||
| extend AccountCustomEntity = Account, HostCustomEntity = Computer;
|
||||
let GroupCreated = SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
// 4727 - A security-enabled global group was created
|
||||
// 4731 - A security-enabled local group was created
|
||||
// 4754 - A security-enabled universal group was created
|
||||
| where EventID in ("4727", "4731", "4754")
|
||||
| where AccountType == "User"
|
||||
| project GroupCreateTime = TimeGenerated, GroupCreateEventID = EventID, GroupCreateActivity = Activity, GroupCreateComputer = Computer,
|
||||
GroupCreateTargetUserName = TargetUserName, GroupCreateTargetDomainName = TargetDomainName, GroupCreateSubjectUserName = SubjectUserName,
|
||||
GroupCreateSubjectDomainName = SubjectDomainName, GroupCreateSubjectUserSid = SubjectUserSid, GroupSid = TargetSid, Account, Computer;
|
||||
GroupCreated
|
||||
| join (
|
||||
GroupAddition
|
||||
) on GroupSid
|
||||
| extend timestamp = GroupCreateTime, AccountCustomEntity = Account, HostCustomEntity = Computer
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
// Name: Hosts with new logons
|
||||
// Description: Shows new 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.
|
||||
//
|
||||
// Id: 62e2df59-1535-4c8e-ac6c-c91faeed0179
|
||||
//
|
||||
// Tactics: #LateralMovement,
|
||||
//
|
||||
let LogonEvents=() {
|
||||
let logonSuccess=SecurityEvent
|
||||
| where EventID==4624
|
||||
| project TimeGenerated, ComputerName=Computer, AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress, ActionType='Logon';
|
||||
let logonFail=SecurityEvent
|
||||
| where EventID==4625
|
||||
| project TimeGenerated, ComputerName=Computer, AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress, ActionType='LogonFailure';
|
||||
logonFail
|
||||
| union logonSuccess
|
||||
};
|
||||
LogonEvents
|
||||
| where TimeGenerated >= ago(14d)
|
||||
| where ActionType == 'Logon'
|
||||
| summarize count() by ComputerName, AccountName
|
||||
| join kind=leftouter (
|
||||
LogonEvents
|
||||
| where TimeGenerated >= ago(1d)
|
||||
| where ActionType == 'Logon'
|
||||
| summarize count() by ComputerName, AccountName
|
||||
) on ComputerName
|
||||
| where AccountName != AccountName1
|
||||
| summarize HostCount=dcount(ComputerName) by AccountName1
|
||||
| extend Name = AccountName1
|
||||
| project Name , HostCount
|
||||
| extend AccountCustomEntity = Name
|
|
@ -0,0 +1,42 @@
|
|||
id: 62e2df59-1535-4c8e-ac6c-c91faeed0179
|
||||
name: Hosts with new logons
|
||||
description: |
|
||||
'Shows new 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.'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- CredentialAccess
|
||||
- LateralMovement
|
||||
relevantTechniques:
|
||||
- T1110
|
||||
query: |
|
||||
|
||||
let starttime = 7d;
|
||||
let endtime = 1d;
|
||||
let LogonEvents=() {
|
||||
let logonSuccess=SecurityEvent
|
||||
| where EventID==4624
|
||||
| project TimeGenerated, ComputerName=Computer, AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress, ActionType='Logon';
|
||||
let logonFail=SecurityEvent
|
||||
| where EventID==4625
|
||||
| project TimeGenerated, ComputerName=Computer, AccountName=TargetUserName, AccountDomain=TargetDomainName, IpAddress, ActionType='LogonFailure';
|
||||
logonFail
|
||||
| union logonSuccess
|
||||
};
|
||||
LogonEvents
|
||||
| where TimeGenerated >= ago(endtime)
|
||||
| where ActionType == 'Logon'
|
||||
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), count() by ComputerName, AccountName
|
||||
| join kind=leftanti (
|
||||
LogonEvents
|
||||
| where TimeGenerated >= ago(starttime)
|
||||
| where ActionType == 'Logon'
|
||||
| summarize count() by ComputerName, AccountName
|
||||
) on ComputerName
|
||||
| summarize StartTimeUtc = min(StartTimeUtc), EndTimeUtc = max(EndTimeUtc), HostCount=dcount(ComputerName) by AccountName
|
||||
| extend timestamp = StartTimeUtc, AccountCustomEntity = AccountName
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
// Name: Least Common Parent And Child Process Pairs
|
||||
// Id: 3712595d-6f47-416b-963a-605201ed2764
|
||||
// Description: Looks across your environment for least common Parent/Child process combinations. Will possibly find some malicious activity disguised as well known process names. By ZanCo
|
||||
// DataSource: #SecurityEvent
|
||||
// Tactics: #InitialAccess, #Execution, #Persistence
|
||||
let Whitelist = dynamic (['foo.exe', 'baz.exe']);
|
||||
let Sensitivity = 5;
|
||||
let StartDate = ago(7d);
|
||||
let Duration = 7d;
|
||||
SecurityEvent
|
||||
| where EventID == 4688 and TimeGenerated > StartDate and TimeGenerated < (StartDate + Duration) and isnotnull(ParentProcessName)
|
||||
| extend ProcArray = split(NewProcessName, '\\'), ParentProcArray = split(ParentProcessName, '\\')
|
||||
// ProcArrayLength is Folder Depth
|
||||
| extend ProcArrayLength = arraylength(ProcArray), ParentProcArrayLength = arraylength(ParentProcArray)
|
||||
| extend LastIndex = ProcArrayLength - 1, ParentLastIndex = ParentProcArrayLength - 1
|
||||
| extend Proc = ProcArray[LastIndex], ParentProc = ParentProcArray[ParentLastIndex]
|
||||
| where Proc !in (Whitelist)
|
||||
| extend ParentChildPair = strcat(ParentProc , ' > ', Proc)
|
||||
| summarize TimesSeen = count(), HostCount = dcount(Computer), Hosts = makeset(Computer), UserCount = dcount(SubjectUserName), Users = makeset(SubjectUserName) by ParentChildPair
|
||||
| where TimesSeen < Sensitivity
|
|
@ -0,0 +1,31 @@
|
|||
id: 3712595d-6f47-416b-963a-605201ed2764
|
||||
name: Least Common Parent And Child Process Pairs
|
||||
description: |
|
||||
'Looks across your environment for least common Parent/Child process combinations.
|
||||
Will possibly find some malicious activity disguised as well known process names.
|
||||
By ZanCo'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Execution
|
||||
query: |
|
||||
|
||||
let Whitelist = dynamic (['foo.exe', 'baz.exe']);
|
||||
let Sensitivity = 5;
|
||||
let StartDate = ago(7d);
|
||||
let Duration = 7d;
|
||||
SecurityEvent
|
||||
| where EventID == 4688 and TimeGenerated > StartDate and TimeGenerated < (StartDate + Duration) and isnotnull(ParentProcessName)
|
||||
| extend ProcArray = split(NewProcessName, '\\'), ParentProcArray = split(ParentProcessName, '\\')
|
||||
// ProcArrayLength is Folder Depth
|
||||
| extend ProcArrayLength = arraylength(ProcArray), ParentProcArrayLength = arraylength(ParentProcArray)
|
||||
| extend LastIndex = ProcArrayLength - 1, ParentLastIndex = ParentProcArrayLength - 1
|
||||
| extend Proc = ProcArray[LastIndex], ParentProc = ParentProcArray[ParentLastIndex]
|
||||
| where Proc !in (Whitelist)
|
||||
| extend ParentChildPair = strcat(ParentProc , ' > ', Proc)
|
||||
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), TimesSeen = count(), HostCount = dcount(Computer), Hosts = makeset(Computer), UserCount = dcount(SubjectUserName), Users = makeset(SubjectUserName) by ParentChildPair
|
||||
| where TimesSeen < Sensitivity
|
||||
| extend timestamp = StartTimeUtc
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// Name: Least Common Processes by Command Line
|
||||
// Id: 088d30e9-c02b-46b1-bd1f-d5b6d6b782f0
|
||||
// Description: Looks across your environment for least common Process Command Lines, may be noisy and require whitelisting. By ZanCo
|
||||
// DataSource: #SecurityEvent
|
||||
// Tactics: #InitialAccess, #Execution, #Persistence
|
||||
let Whitelist = dynamic (['foo.exe', 'baz.exe']);
|
||||
let Sensitivity = 5;
|
||||
let StartDate = ago(7d);
|
||||
let Duration = 7d;
|
||||
SecurityEvent
|
||||
| where EventID == 4688 and TimeGenerated > StartDate and TimeGenerated < (StartDate + Duration) and NewProcessName !endswith 'conhost.exe'
|
||||
| extend ProcArray = split(NewProcessName, '\\')
|
||||
// ProcArrayLength is Folder Depth
|
||||
| extend ProcArrayLength = arraylength(ProcArray)
|
||||
| extend LastIndex = ProcArrayLength - 1
|
||||
| extend Proc = ProcArray[LastIndex]
|
||||
| where Proc !in (Whitelist)
|
||||
| summarize TimesSeen = count(), HostCount = dcount(Computer), Hosts = makeset(Computer), UserCount = dcount(SubjectUserName), Users = makeset(SubjectUserName) by CommandLine
|
||||
| where TimesSeen < Sensitivity
|
|
@ -0,0 +1,28 @@
|
|||
id: 088d30e9-c02b-46b1-bd1f-d5b6d6b782f0
|
||||
name: Least Common Processes by Command Line
|
||||
description: |
|
||||
'Looks across your environment for least common Process Command Lines, may be noisy and require whitelisting. By ZanCo'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Execution
|
||||
query: |
|
||||
|
||||
let Whitelist = dynamic (['foo.exe', 'baz.exe']);
|
||||
let Sensitivity = 5;
|
||||
let StartDate = ago(7d);
|
||||
let Duration = 7d;
|
||||
SecurityEvent
|
||||
| where EventID == 4688 and TimeGenerated > StartDate and TimeGenerated < (StartDate + Duration) and NewProcessName !endswith 'conhost.exe'
|
||||
| extend ProcArray = split(NewProcessName, '\\')
|
||||
// ProcArrayLength is Folder Depth
|
||||
| extend ProcArrayLength = arraylength(ProcArray)
|
||||
| extend LastIndex = ProcArrayLength - 1
|
||||
| extend Proc = ProcArray[LastIndex]
|
||||
| where Proc !in (Whitelist)
|
||||
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), TimesSeen = count(), HostCount = dcount(Computer), Hosts = makeset(Computer), UserCount = dcount(SubjectUserName), Users = makeset(SubjectUserName) by CommandLine
|
||||
| where TimesSeen < Sensitivity
|
||||
| extend timestamp = StartTimeUtc
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
// Name: Least Common Processes Including Folder Depth
|
||||
//
|
||||
// Id: 6d04a1ef-1b4d-4ff8-a76c-ad7d1a396136
|
||||
//
|
||||
// Description: Looks across your environment for least commonly occurring Processes. To observe for commonly known process names, this hunting query will also look at the process' depth from the root. We don't compare full process path due to some processes having dynamic folder names. By ZanCo
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #InitialAccess, #Execution, #Persistence
|
||||
//
|
||||
let Whitelist = dynamic (['foo.exe', 'baz.exe']);
|
||||
let Sensitivity = 15;
|
||||
let StartDate = ago(7d);
|
||||
let Duration = 7d;
|
||||
SecurityEvent
|
||||
| where EventID == 4688 and TimeGenerated > StartDate and TimeGenerated < (StartDate + Duration)
|
||||
| extend ProcArray = split(NewProcessName, '\\')
|
||||
// ProcArrayLength is Folder Depth
|
||||
| extend ProcArrayLength = arraylength(ProcArray)
|
||||
| extend LastIndex = ProcArrayLength - 1
|
||||
| extend Proc = ProcArray[LastIndex]
|
||||
| where Proc !in (Whitelist)
|
||||
// ProcArray[0] is the proc's Drive
|
||||
| extend DriveDepthProc = strcat(ProcArray[0], '-', ProcArrayLength, '-', Proc)
|
||||
| summarize TimesSeen = count(), HostCount = dcount(Computer), Hosts = makeset(Computer), UserCount = dcount(SubjectUserName), Users = makeset(SubjectUserName) by DriveDepthProc
|
||||
| where TimesSeen < Sensitivity
|
|
@ -0,0 +1,29 @@
|
|||
id: 6d04a1ef-1b4d-4ff8-a76c-ad7d1a396136
|
||||
name: Least Common Processes Including Folder Depth
|
||||
description: |
|
||||
'Looks across your environment for least common Process Command Lines, may be noisy and require whitelisting. By ZanCo'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Execution
|
||||
query: |
|
||||
|
||||
let Whitelist = dynamic (['foo.exe', 'baz.exe']);
|
||||
let Sensitivity = 15;
|
||||
let StartDate = ago(7d);
|
||||
let Duration = 7d;
|
||||
SecurityEvent
|
||||
| where EventID == 4688 and TimeGenerated > StartDate and TimeGenerated < (StartDate + Duration)
|
||||
| extend ProcArray = split(NewProcessName, '\\')
|
||||
// ProcArrayLength is Folder Depth
|
||||
| extend ProcArrayLength = arraylength(ProcArray)
|
||||
| extend LastIndex = ProcArrayLength - 1
|
||||
| extend Proc = ProcArray[LastIndex]
|
||||
| where Proc !in (Whitelist)
|
||||
// ProcArray[0] is the proc's Drive
|
||||
| extend DriveDepthProc = strcat(ProcArray[0], '-', ProcArrayLength, '-', Proc)
|
||||
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), TimesSeen = count(), HostCount = dcount(Computer), Hosts = makeset(Computer), UserCount = dcount(SubjectUserName), Users = makeset(SubjectUserName) by DriveDepthProc
|
||||
| where TimesSeen < Sensitivity
|
||||
| extend timestamp = StartTimeUtc
|
|
@ -1,76 +0,0 @@
|
|||
// Name: Entropy for Processes for a given Host
|
||||
// Description: Entropy calculation used to help identify Hosts where they have a high variety of processes(a high entropy process list on a given Host over time).
|
||||
// This helps us identify rare processes on a given Host. Rare here means a process shows up on the Host relatively few times in the the last 7days.
|
||||
// The Weight is calculated based on the Entropy, Process Count and Distinct Hosts with that Process. The lower the Weight/ProcessEntropy the, more interesting.
|
||||
// The Weight calculation increases the Weight if the process executes more than once on the Host or has executed on more than 1 Hosts.
|
||||
// In general, this should identify processes on a Host that are rare and rare for the environment.
|
||||
//
|
||||
// References: https://medium.com/udacity/shannon-entropy-information-gain-and-picking-balls-from-buckets-5810d35d54b4
|
||||
// https://en.wiktionary.org/wiki/Shannon_entropy
|
||||
//
|
||||
// Id: 05208917-82de-46f7-a190-a65739a690f4
|
||||
//
|
||||
// DataSource: ##SecurityEvent
|
||||
//
|
||||
// Tactics: #Execution
|
||||
//
|
||||
// May need to reduce the number of days if the environment is very large. Try 3-5 days, but less accuracy.
|
||||
let end = startofday(now());
|
||||
let start = end - 7d;
|
||||
let Exclude = SecurityEvent
|
||||
// Timeframe is set so that results do not change during the same day (UTC time)
|
||||
| where TimeGenerated >= start and TimeGenerated <= end
|
||||
| where EventID == 4688
|
||||
| summarize count() by Process
|
||||
// Removing noisy processes for an environment, adjust as needed
|
||||
| where count_ >= 100000;
|
||||
let AllSecEvents = SecurityEvent
|
||||
| where TimeGenerated >= start and TimeGenerated <= end
|
||||
| where EventID == 4688
|
||||
| where Process !in~ ("conhost.exe")
|
||||
| project Computer, Process;
|
||||
// Removing noisy process from full list
|
||||
let Include = Exclude | join kind= rightanti (
|
||||
AllSecEvents
|
||||
) on Process;
|
||||
// Identifying prevalence for a given process in the environment
|
||||
let DCwPC = Include | summarize DistinctComputersWithProcessCount = dcount(Computer) by Process
|
||||
| join kind=inner (
|
||||
Include
|
||||
) on Process
|
||||
| distinct Computer, Process, DistinctComputersWithProcessCount;
|
||||
// Getting the Total process count on each host to use as the denominator in the entropy calc
|
||||
let TPCoH = Include | summarize TotalProcessCountOnHost = count(Process) by Computer
|
||||
| join kind=inner (
|
||||
Include
|
||||
) on Computer
|
||||
| distinct Computer, Process, TotalProcessCountOnHost
|
||||
//Getting a decimal value for later computation
|
||||
| extend TPCoHValue = TotalProcessCountOnHost*1.0;
|
||||
// Need the count of each class in my bucket or also said as count of ProcName(Class) per Host(Bucket) for use in the entropy calc
|
||||
let PCoH = Include | summarize ProcessCountOnHost = count(Process) by Computer, Process
|
||||
| join kind=inner (
|
||||
Include
|
||||
) on Computer,Process
|
||||
| distinct Computer, Process, ProcessCountOnHost
|
||||
//Getting a decimal value for later computation
|
||||
| extend PCoHValue = ProcessCountOnHost*1.0;
|
||||
let Combined = DCwPC | join ( TPCoH ) on Computer, Process | join ( PCoH ) on Computer, Process;
|
||||
let Results = Combined
|
||||
// Entropy calculation
|
||||
| extend ProcessEntropy = -log2(PCoHValue/TPCoHValue)*(PCoHValue/TPCoHValue)
|
||||
// Calculating Weight, see details in description
|
||||
| extend Weight = toreal((ProcessEntropy*100000)*ProcessCountOnHost*DistinctComputersWithProcessCount)
|
||||
| where Weight <= 100
|
||||
| project Computer, Process, Weight , ProcessEntropy, TotalProcessCountOnHost, ProcessCountOnHost, DistinctComputersWithProcessCount;
|
||||
// Join back full entry
|
||||
Results | join kind= inner (
|
||||
SecurityEvent
|
||||
| where TimeGenerated >= start and TimeGenerated <= end
|
||||
| where EventID == 4688
|
||||
| where Process !in~ ("conhost.exe")
|
||||
| project TimeGenerated, EventID, Computer, SubjectUserSid, Account, AccountType, Process, NewProcessName, CommandLine, ParentProcessName
|
||||
) on Computer, Process
|
||||
| project TimeGenerated, EventID, Computer, SubjectUserSid, Account, Weight, ProcessEntropy, Process, NewProcessName, CommandLine, ParentProcessName, TotalProcessCountOnHost, ProcessCountOnHost, DistinctComputersWithProcessCount
|
||||
| sort by Weight asc, ProcessEntropy asc, NewProcessName asc
|
||||
| extend HostCustomEntity = Computer, AccountCustomEntity = Account
|
|
@ -0,0 +1,79 @@
|
|||
id: 05208917-82de-46f7-a190-a65739a690f4
|
||||
name: Entropy for Processes for a given Host
|
||||
description: |
|
||||
'Entropy calculation used to help identify Hosts where they have a high variety of processes(a high entropy process list on a given Host over time).
|
||||
This helps us identify rare processes on a given Host. Rare here means a process shows up on the Host relatively few times in the the last 7days.
|
||||
The Weight is calculated based on the Entropy, Process Count and Distinct Hosts with that Process. The lower the Weight/ProcessEntropy the, more interesting.
|
||||
The Weight calculation increases the Weight if the process executes more than once on the Host or has executed on more than 1 Hosts.
|
||||
In general, this should identify processes on a Host that are rare and rare for the environment.
|
||||
References: https://medium.com/udacity/shannon-entropy-information-gain-and-picking-balls-from-buckets-5810d35d54b4
|
||||
https://en.wiktionary.org/wiki/Shannon_entropy'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Execution
|
||||
query: |
|
||||
|
||||
// May need to reduce the number of days if the environment is very large. Try 3-5 days, but less accuracy.
|
||||
let end = startofday(now());
|
||||
let start = end - 7d;
|
||||
let Exclude = SecurityEvent
|
||||
// Timeframe is set so that results do not change during the same day (UTC time)
|
||||
| where TimeGenerated >= start and TimeGenerated <= end
|
||||
| where EventID == 4688
|
||||
| summarize count() by Process
|
||||
// Removing noisy processes for an environment, adjust as needed
|
||||
| where count_ >= 100000;
|
||||
let AllSecEvents = SecurityEvent
|
||||
| where TimeGenerated >= start and TimeGenerated <= end
|
||||
| where EventID == 4688
|
||||
| where Process !in~ ("conhost.exe")
|
||||
| project Computer, Process;
|
||||
// Removing noisy process from full list
|
||||
let Include = Exclude | join kind= rightanti (
|
||||
AllSecEvents
|
||||
) on Process;
|
||||
// Identifying prevalence for a given process in the environment
|
||||
let DCwPC = Include | summarize DistinctComputersWithProcessCount = dcount(Computer) by Process
|
||||
| join kind=inner (
|
||||
Include
|
||||
) on Process
|
||||
| distinct Computer, Process, DistinctComputersWithProcessCount;
|
||||
// Getting the Total process count on each host to use as the denominator in the entropy calc
|
||||
let TPCoH = Include | summarize TotalProcessCountOnHost = count(Process) by Computer
|
||||
| join kind=inner (
|
||||
Include
|
||||
) on Computer
|
||||
| distinct Computer, Process, TotalProcessCountOnHost
|
||||
//Getting a decimal value for later computation
|
||||
| extend TPCoHValue = TotalProcessCountOnHost*1.0;
|
||||
// Need the count of each class in my bucket or also said as count of ProcName(Class) per Host(Bucket) for use in the entropy calc
|
||||
let PCoH = Include | summarize ProcessCountOnHost = count(Process) by Computer, Process
|
||||
| join kind=inner (
|
||||
Include
|
||||
) on Computer,Process
|
||||
| distinct Computer, Process, ProcessCountOnHost
|
||||
//Getting a decimal value for later computation
|
||||
| extend PCoHValue = ProcessCountOnHost*1.0;
|
||||
let Combined = DCwPC | join ( TPCoH ) on Computer, Process | join ( PCoH ) on Computer, Process;
|
||||
let Results = Combined
|
||||
// Entropy calculation
|
||||
| extend ProcessEntropy = -log2(PCoHValue/TPCoHValue)*(PCoHValue/TPCoHValue)
|
||||
// Calculating Weight, see details in description
|
||||
| extend Weight = toreal((ProcessEntropy*100000)*ProcessCountOnHost*DistinctComputersWithProcessCount)
|
||||
| where Weight <= 100
|
||||
| project Computer, Process, Weight , ProcessEntropy, TotalProcessCountOnHost, ProcessCountOnHost, DistinctComputersWithProcessCount;
|
||||
// Join back full entry
|
||||
Results | join kind= inner (
|
||||
SecurityEvent
|
||||
| where TimeGenerated >= start and TimeGenerated <= end
|
||||
| where EventID == 4688
|
||||
| where Process !in~ ("conhost.exe")
|
||||
| project TimeGenerated, EventID, Computer, SubjectUserSid, Account, AccountType, Process, NewProcessName, CommandLine, ParentProcessName
|
||||
) on Computer, Process
|
||||
| project TimeGenerated, EventID, Computer, SubjectUserSid, Account, Weight, ProcessEntropy, Process, NewProcessName, CommandLine, ParentProcessName, TotalProcessCountOnHost, ProcessCountOnHost, DistinctComputersWithProcessCount
|
||||
| sort by Weight asc, ProcessEntropy asc, NewProcessName asc
|
||||
| extend timestamp = TimeGenerated, HostCustomEntity = Computer, AccountCustomEntity = Account
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
// Name: Rare processes run by Service accounts
|
||||
// Description: Service accounts normally are supposed to perform a limited set of tasks in a stable environment.
|
||||
// The query collects a list of service account and then joins them with rare processes in an environment to detect anomalous behaviours.
|
||||
//
|
||||
//Id: af02987c-949d-47d5-b0ae-64d8e1b674e2
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #Persistence, #Discovery, #LateralMovement , #InitialAccess, #Execution,
|
||||
//
|
||||
let List1 = datatable(AccountName:string)["MSSQLSERVER", "ReportServer", "MSDTSServer100", "IUSR"];
|
||||
// Provide a list of service account/ built-in accounts in an environment.
|
||||
let List2 = SecurityEvent
|
||||
// Self generating a list of Service account using event Id :4624
|
||||
| where TimeGenerated >= ago(1d)
|
||||
| where EventID == "4624"
|
||||
| where Account !contains "$" and Account !contains "Local SYSTEM" and Account !contains "Local SERVICE" and Account !contains "Network SERVICE" and Account !contains "NT AUTHORITY" and Account !contains "NT-AUTORITÄT"
|
||||
| where LogonType == "5"
|
||||
| extend AccountName = Account
|
||||
| distinct AccountName;
|
||||
let Accounts = List1 | union (List2 | distinct AccountName);
|
||||
let ProcessCreationEvents=() {
|
||||
let processEvents=SecurityEvent
|
||||
| where TimeGenerated >= ago(1d)
|
||||
| where EventID==4688
|
||||
// filter out common randomly named files related to MSI installers and browsers
|
||||
| where not(NewProcessName matches regex @"\\TRA[0-9A-Fa-f]{3}\.tmp")
|
||||
| where not(NewProcessName matches regex @"\\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
|
||||
// normalize guids
|
||||
| project TimeGenerated, AccountName, 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 digits away
|
||||
| project TimeGenerated, AccountName, FileName=replace(@'\d', 'n', FileName);
|
||||
let freqs = normalizedProcesses
|
||||
| summarize frequency = count() by FileName
|
||||
| join kind= leftouter (
|
||||
normalizedProcesses
|
||||
| summarize Since=min(TimeGenerated), LastSeen=max(TimeGenerated) by FileName, AccountName
|
||||
) on FileName;
|
||||
let Finalfreqs = freqs
|
||||
| where frequency <= toscalar( freqs | serialize | project frequency | summarize percentiles(frequency, 10))
|
||||
| order by frequency asc
|
||||
| project FileName, frequency, Since, LastSeen , AccountName
|
||||
// restrict results to unusual processes seen in last day
|
||||
| where LastSeen >= ago(1d);
|
||||
Accounts
|
||||
| join kind= inner (
|
||||
Finalfreqs
|
||||
) on AccountName
|
||||
| where frequency < 10
|
||||
| project-away AccountName1
|
|
@ -0,0 +1,69 @@
|
|||
id: af02987c-949d-47d5-b0ae-64d8e1b674e2
|
||||
name: Rare processes run by Service accounts
|
||||
description: |
|
||||
'Service accounts normally are supposed to perform a limited set of tasks in a stable environment.
|
||||
The query collects a list of service account and then joins them with rare processes in an environment to detect anomalous behaviours.'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Execution
|
||||
query: |
|
||||
|
||||
let timeframe = 1d;
|
||||
let List1 = datatable(AccountName:string)["MSSQLSERVER", "ReportServer", "MSDTSServer100", "IUSR"];
|
||||
// Provide a list of service account/ built-in accounts in an environment.
|
||||
let List2 = SecurityEvent
|
||||
// Self generating a list of Service account using event Id :4624
|
||||
| where TimeGenerated >= ago(timeframe)
|
||||
| where EventID == "4624"
|
||||
| where Account !contains "$" and Account !contains "Local SYSTEM" and Account !contains "Local SERVICE" and Account !contains "Network SERVICE" and Account !contains "NT AUTHORITY" and Account !contains "NT-AUTORITÄT"
|
||||
| where LogonType == "5"
|
||||
| extend AccountName = Account
|
||||
| distinct AccountName;
|
||||
let Accounts = List1 | union (List2 | distinct AccountName);
|
||||
let ProcessCreationEvents=() {
|
||||
let processEvents=SecurityEvent
|
||||
| where TimeGenerated >= ago(timeframe)
|
||||
| where EventID==4688
|
||||
// filter out common randomly named files related to MSI installers and browsers
|
||||
| where not(NewProcessName matches regex @"\\TRA[0-9A-Fa-f]{3}\.tmp")
|
||||
| where not(NewProcessName matches regex @"\\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
|
||||
// normalize guids
|
||||
| project TimeGenerated, AccountName, 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 digits away
|
||||
| project TimeGenerated, AccountName, FileName=replace(@'\d', 'n', FileName);
|
||||
let freqs = normalizedProcesses
|
||||
| summarize frequency = count() by FileName
|
||||
| join kind= leftouter (
|
||||
normalizedProcesses
|
||||
| summarize Since=min(TimeGenerated), LastSeen=max(TimeGenerated) by FileName, AccountName
|
||||
) on FileName;
|
||||
let Finalfreqs = freqs
|
||||
| where frequency <= toscalar( freqs | serialize | project frequency | summarize percentiles(frequency, 10))
|
||||
| order by frequency asc
|
||||
| project FileName, frequency, Since, LastSeen , AccountName
|
||||
// restrict results to unusual processes seen in last day
|
||||
| where LastSeen >= ago(timeframe);
|
||||
Accounts
|
||||
| join kind= inner (
|
||||
Finalfreqs
|
||||
) on AccountName
|
||||
| where frequency < 10
|
||||
| project-away AccountName1
|
||||
| extend AccountCustomEntity = AccountName
|
|
@ -1,11 +0,0 @@
|
|||
// 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.
|
||||
//
|
||||
// Id: d0f13bb9-e713-4f89-b610-1806326a1dea
|
||||
//
|
||||
// Tactics: #InitialAccess, #LateralMovement, #Persistence
|
||||
//
|
||||
SecurityEvent
|
||||
| where EventID in (4624, 4625)
|
||||
| where AccountType == 'User'
|
||||
| summarize Amount = count() by LogonTypeName
|
|
@ -0,0 +1,23 @@
|
|||
id: d0f13bb9-e713-4f89-b610-1806326a1dea
|
||||
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.'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- CredentialAccess
|
||||
- LateralMovement
|
||||
relevantTechniques:
|
||||
- T1110
|
||||
query: |
|
||||
|
||||
let timeframe = 1d;
|
||||
SecurityEvent
|
||||
| where TimeGenerated >= ago(timeframe)
|
||||
| where EventID in (4624, 4625)
|
||||
| where AccountType == 'User'
|
||||
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), Amount = count() by LogonTypeName
|
||||
| extend timestamp = StartTimeUtc
|
|
@ -1,26 +0,0 @@
|
|||
// Name: User Account added to Built in Domain Local or Global Group over last 10 days
|
||||
// Description: User account was added to a privileged built in domain local group or global group such as the Enterprise Adminis, Cert Publishers or DnsAdmins
|
||||
// Be sure to verify this is an expected addition
|
||||
//
|
||||
// Id: 8d69a665-074a-443b-aae6-5dd9bdd5cfb1
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #Persistence, #Discovery, #LateralMovement, #Collection
|
||||
//
|
||||
let timeframe = 10d;
|
||||
// For AD SID mappings - https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/active-directory-security-groups
|
||||
let WellKnownLocalSID = "S-1-5-32-5[0-9][0-9]";
|
||||
let WellKnownGroupSID = "S-1-5-21-[0-9]*-[0-9]*-[0-9]*-5[0-9][0-9]|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1102|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1103";
|
||||
SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
| where AccountType == "User"
|
||||
// 4728 - A member was added to a security-enabled global group
|
||||
// 4732 - A member was added to a security-enabled local group
|
||||
// 4756 - A member was added to a security-enabled universal group
|
||||
| where EventID in ("4728", "4732", "4756")
|
||||
| where TargetSid matches regex WellKnownLocalSID or TargetSid matches regex WellKnownGroupSID
|
||||
// Exclude Remote Desktop Users group: S-1-5-32-555
|
||||
| where TargetSid !in ("S-1-5-32-555")
|
||||
| project StartTimeUtc = TimeGenerated, EventID, Activity, Computer, TargetUserName, TargetDomainName, TargetSid, UserPrincipalName, SubjectUserName, SubjectUserSid
|
||||
| extend HostCustomEntity = Computer, AccountCustomEntity = UserPrincipalName
|
|
@ -0,0 +1,34 @@
|
|||
id: 8d69a665-074a-443b-aae6-5dd9bdd5cfb1
|
||||
name: User Account added to Built in Domain Local or Global Group
|
||||
description: |
|
||||
'User account was added to a privileged built in domain local group or global group such as the Enterprise Adminis, Cert Publishers or DnsAdmins
|
||||
Be sure to verify this is an expected addition.'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Persistence
|
||||
- PrivilegeEscalation
|
||||
relevantTechniques:
|
||||
- T1098
|
||||
- T1078
|
||||
query: |
|
||||
|
||||
let timeframe = 10d;
|
||||
// For AD SID mappings - https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/active-directory-security-groups
|
||||
let WellKnownLocalSID = "S-1-5-32-5[0-9][0-9]";
|
||||
let WellKnownGroupSID = "S-1-5-21-[0-9]*-[0-9]*-[0-9]*-5[0-9][0-9]|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1102|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1103";
|
||||
SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
| where AccountType == "User"
|
||||
// 4728 - A member was added to a security-enabled global group
|
||||
// 4732 - A member was added to a security-enabled local group
|
||||
// 4756 - A member was added to a security-enabled universal group
|
||||
| where EventID in ("4728", "4732", "4756")
|
||||
| where TargetSid matches regex WellKnownLocalSID or TargetSid matches regex WellKnownGroupSID
|
||||
// Exclude Remote Desktop Users group: S-1-5-32-555
|
||||
| where TargetSid !in ("S-1-5-32-555")
|
||||
| project StartTimeUtc = TimeGenerated, EventID, Activity, Computer, TargetUserName, TargetDomainName, TargetSid, UserPrincipalName, SubjectUserName, SubjectUserSid
|
||||
| extend timestamp = StartTimeUtc, HostCustomEntity = Computer, AccountCustomEntity = UserPrincipalName
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
// Name: User Account Created and Deleted within 10mins
|
||||
// Description: User account created and then deleted within 10 minutes across last 30 days
|
||||
//
|
||||
// Id: 6135a90e-ba30-4f36-9b6a-3a350050704b
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #Persistence, #Discovery, #LateralMovement, #Collection
|
||||
//
|
||||
// TimeFrame is the number of lookback days, default is last 14 days
|
||||
let timeframe = 14d;
|
||||
// TimeDelta is the difference between when the account was created and when it was deleted, default is set to 10min or less
|
||||
let timedelta = 10m;
|
||||
SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
// A user account was created
|
||||
| where EventID == "4720"
|
||||
| where AccountType == "User"
|
||||
| project creationTime = TimeGenerated, CreateEventID = EventID, Activity, Computer, TargetUserName, UserPrincipalName, AccountUsedToCreate = SubjectUserName, TargetSid, SubjectUserSid
|
||||
| join kind= inner (
|
||||
SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
// A user account was deleted
|
||||
| where EventID == "4726"
|
||||
| where AccountType == "User"
|
||||
| project deletionTime = TimeGenerated, DeleteEventID = EventID, Activity, Computer, TargetUserName, UserPrincipalName, AccountUsedToDelete = SubjectUserName, TargetSid, SubjectUserSid
|
||||
) on Computer, TargetUserName
|
||||
| where deletionTime - creationTime < 10m
|
||||
| extend TimeDelta = deletionTime - creationTime
|
||||
| where tolong(TimeDelta) >= 0
|
||||
| project TimeDelta, creationTime, CreateEventID, Computer, TargetUserName, UserPrincipalName, AccountUsedToCreate, deletionTime, DeleteEventID, AccountUsedToDelete
|
||||
| extend HostCustomEntity = Computer, AccountCustomEntity = UserPrincipalName
|
|
@ -0,0 +1,43 @@
|
|||
id: 6135a90e-ba30-4f36-9b6a-3a350050704b
|
||||
name: Long lookback User Account Created and Deleted within 10mins
|
||||
description: |
|
||||
'User account created and then deleted within 10 minutes across last 14 days'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Persistence
|
||||
- PrivilegeEscalation
|
||||
relevantTechniques:
|
||||
- T1098
|
||||
- T1078
|
||||
query: |
|
||||
|
||||
// TimeFrame is the number of lookback days, default is last 14 days
|
||||
let timeframe = 14d;
|
||||
// TimeDelta is the difference between when the account was created and when it was deleted, default is set to 10min or less
|
||||
let timedelta = 10m;
|
||||
SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
// A user account was created
|
||||
| where EventID == "4720"
|
||||
| where AccountType == "User"
|
||||
| project creationTime = TimeGenerated, CreateEventID = EventID, Activity, Computer, TargetUserName, UserPrincipalName,
|
||||
AccountUsedToCreate = SubjectUserName, TargetSid, SubjectUserSid
|
||||
| join kind= inner (
|
||||
SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
// A user account was deleted
|
||||
| where EventID == "4726"
|
||||
| where AccountType == "User"
|
||||
| project deletionTime = TimeGenerated, DeleteEventID = EventID, Activity, Computer, TargetUserName, UserPrincipalName,
|
||||
AccountUsedToDelete = SubjectUserName, TargetSid, SubjectUserSid
|
||||
) on Computer, TargetUserName
|
||||
| where deletionTime - creationTime < timedelta
|
||||
| extend TimeDelta = deletionTime - creationTime
|
||||
| where tolong(TimeDelta) >= 0
|
||||
| project TimeDelta, creationTime, CreateEventID, Computer, TargetUserName, UserPrincipalName, AccountUsedToCreate,
|
||||
deletionTime, DeleteEventID, AccountUsedToDelete
|
||||
| extend timestamp = creationTime, HostCustomEntity = Computer, AccountCustomEntity = UserPrincipalName
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
// Name: User account added or removed from a security group by an unauthorized user
|
||||
// Description: User account added or removed from a security group by an unauthorized user, pass in a list
|
||||
//
|
||||
// Id: d57f675c-ad6c-44d0-95fb-3bf707e70155
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #Persistence, #Discovery, #LateralMovement, #PrivilegeEscalation
|
||||
//
|
||||
// Create DataTable with your own values, example below shows dummy usernames that are authorized and for what domain
|
||||
let List = datatable(AuthorizedUser:string, Domain:string)["Bob", "Domain", "joe", "domain", "MATT", "DOMAIN"];
|
||||
let timeframe = 1d;
|
||||
SecurityEvent
|
||||
| where TimeGenerated >= ago(timeframe)
|
||||
| where EventID in (4728, 4729, 4732, 4733, 4746, 4747, 4751, 4752, 4756, 4757, 4761, 4762)
|
||||
| join kind= leftanti (
|
||||
List
|
||||
| project SubjectUserName = tolower(AuthorizedUser), SubjectDomainName = toupper(Domain)
|
||||
) on SubjectUserName, SubjectDomainName
|
||||
| project TimeGenerated, Computer, Account, SubjectUserName, SubjectDomainName, TargetAccount, EventID, Activity
|
||||
| extend HostCustomEntity = Computer, AccountCustomEntity = Account
|
|
@ -0,0 +1,29 @@
|
|||
id: d57f675c-ad6c-44d0-95fb-3bf707e70155
|
||||
name: User account added or removed from a security group by an unauthorized user
|
||||
description: |
|
||||
'User account added or removed from a security group by an unauthorized user, pass in a list'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Persistence
|
||||
- PrivilegeEscalation
|
||||
relevantTechniques:
|
||||
- T1098
|
||||
- T1078
|
||||
query: |
|
||||
|
||||
// Create DataTable with your own values, example below shows dummy usernames that are authorized and for what domain
|
||||
let List = datatable(AuthorizedUser:string, Domain:string)["Bob", "Domain", "joe", "domain", "MATT", "DOMAIN"];
|
||||
let timeframe = 1d;
|
||||
SecurityEvent
|
||||
| where TimeGenerated >= ago(timeframe)
|
||||
| where EventID in (4728, 4729, 4732, 4733, 4746, 4747, 4751, 4752, 4756, 4757, 4761, 4762)
|
||||
| join kind= leftanti (
|
||||
List
|
||||
| project SubjectUserName = tolower(AuthorizedUser), SubjectDomainName = toupper(Domain)
|
||||
) on SubjectUserName, SubjectDomainName
|
||||
| project TimeGenerated, Computer, Account, SubjectUserName, SubjectDomainName, TargetAccount, EventID, Activity
|
||||
| extend timestamp = TimeGenerated, HostCustomEntity = Computer, AccountCustomEntity = Account
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
// Name: User created by unauthorized user
|
||||
// Description: User account created by an unauthorized user, pass in a list
|
||||
//
|
||||
// Id: 42ae9690-89ce-4063-9a90-465badad5395
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #Persistence, #Discovery, #LateralMovement, #PrivilegeEscalation
|
||||
//
|
||||
// Create DataTable with your own values, example below shows dummy usernames that are authorized and for what domain
|
||||
let List = datatable(AuthorizedUser:string, Domain:string)["Bob", "Domain", "joe", "domain", "MATT", "DOMAIN"];
|
||||
let timeframe = 1d;
|
||||
SecurityEvent
|
||||
| where TimeGenerated >= ago(timeframe)
|
||||
| where EventID == 4720
|
||||
| where AccountType == "User"
|
||||
| join kind= leftanti (
|
||||
List
|
||||
| project SubjectUserName = tolower(AuthorizedUser), SubjectDomainName = toupper(Domain)
|
||||
) on SubjectUserName, SubjectDomainName
|
||||
| project TimeGenerated, Computer, Account, SubjectUserName, SubjectDomainName, TargetAccount, EventID, Activity
|
||||
| extend HostCustomEntity = Computer, AccountCustomEntity = Account
|
|
@ -0,0 +1,30 @@
|
|||
id: 42ae9690-89ce-4063-9a90-465badad5395
|
||||
name: User created by unauthorized user
|
||||
description: |
|
||||
'User account created by an unauthorized user, pass in a list'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Persistence
|
||||
- PrivilegeEscalation
|
||||
relevantTechniques:
|
||||
- T1098
|
||||
- T1078
|
||||
query: |
|
||||
|
||||
// Create DataTable with your own values, example below shows dummy usernames that are authorized and for what domain
|
||||
let List = datatable(AuthorizedUser:string, Domain:string)["Bob", "Domain", "joe", "domain", "MATT", "DOMAIN"];
|
||||
let timeframe = 1d;
|
||||
SecurityEvent
|
||||
| where TimeGenerated >= ago(timeframe)
|
||||
| where EventID == 4720
|
||||
| where AccountType == "User"
|
||||
| join kind= leftanti (
|
||||
List
|
||||
| project SubjectUserName = tolower(AuthorizedUser), SubjectDomainName = toupper(Domain)
|
||||
) on SubjectUserName, SubjectDomainName
|
||||
| project TimeGenerated, Computer, Account, SubjectUserName, SubjectDomainName, TargetAccount, EventID, Activity
|
||||
| extend timestamp = TimeGenerated, HostCustomEntity = Computer, AccountCustomEntity = Account
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
// Name: VIP account more than 6 failed logons in 10
|
||||
// Description: VIP Account with more than 6 failed logon attempts in 10 minutes, include your own VIP list in the table below
|
||||
//
|
||||
// Id: e8d36582-c403-4466-bd44-ebede5b6fa6e
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #Discovery, #LateralMovement
|
||||
//
|
||||
// Create DataTable with your own values, example below shows dummy usernames that are authorized and for what domain
|
||||
let List = datatable(VIPUser:string, Domain:string)["Bob", "Domain", "joe", "domain", "MATT", "DOMAIN"];
|
||||
let timeframe = 10m;
|
||||
List | extend Account = strcat(Domain,"\\",VIPUser) | join kind= inner (
|
||||
SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
| where EventID == "4625"
|
||||
| where AccountType == "User"
|
||||
| where LogonType == "2" or LogonType == "3"
|
||||
) on Account
|
||||
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), FailedVIPLogons = count() by LogonType, Account
|
||||
| where FailedVIPLogons >= 6
|
||||
| extend AccountCustomEntity = Account
|
|
@ -0,0 +1,28 @@
|
|||
id: e8d36582-c403-4466-bd44-ebede5b6fa6e
|
||||
name: VIP account more than 6 failed logons in 10
|
||||
description: |
|
||||
'VIP Account with more than 6 failed logon attempts in 10 minutes, include your own VIP list in the table below'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- CredentialAccess
|
||||
relevantTechniques:
|
||||
- T1110
|
||||
query: |
|
||||
|
||||
// Create DataTable with your own values, example below shows dummy usernames that are authorized and for what domain
|
||||
let List = datatable(VIPUser:string, Domain:string)["Bob", "Domain", "joe", "domain", "MATT", "DOMAIN"];
|
||||
let timeframe = 10m;
|
||||
List | extend Account = strcat(Domain,"\\",VIPUser) | join kind= inner (
|
||||
SecurityEvent
|
||||
| where TimeGenerated > ago(timeframe)
|
||||
| where EventID == "4625"
|
||||
| where AccountType == "User"
|
||||
| where LogonType == "2" or LogonType == "3"
|
||||
) on Account
|
||||
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), FailedVIPLogons = count() by LogonType, Account
|
||||
| where FailedVIPLogons >= 6
|
||||
| extend timestamp = StartTimeUtc, AccountCustomEntity = Account
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
// Name: Cscript script daily summary breakdown
|
||||
//
|
||||
// Id: 36abe031-962d-482e-8e1e-a556ed99d5a3
|
||||
//
|
||||
// Description: breakdown of scripts running in the environment
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #Execution
|
||||
//
|
||||
let ProcessCreationEvents=() {
|
||||
let processEvents=SecurityEvent
|
||||
| where EventID==4688
|
||||
| project EventTime=TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
|
||||
FileName=tostring(split(NewProcessName, '\\')[-1]),
|
||||
ProcessCommandLine = CommandLine,
|
||||
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
|
||||
processEvents;
|
||||
};
|
||||
// Daily summary of cscript activity – extracting script name and parameters from commandline:
|
||||
ProcessCreationEvents | where FileName =~ "cscript.exe"
|
||||
| project removeSwitches = replace(@"/+[a-zA-Z0-9:]+", "", ProcessCommandLine) // remove commandline switches
|
||||
| project CommandLine = trim(@"[a-zA-Z0-9\\:""]*cscript(.exe)?("")?(\s)+", removeSwitches) // remove the leading cscript.exe process name
|
||||
// extract the script name:
|
||||
| project ScriptName= iff(CommandLine startswith @"""",
|
||||
extract(@"([:\\a-zA-Z_\-\s0-9\.()]+)(""?)", 0, CommandLine), // handle case where script name is enclosed in " characters
|
||||
extract(@"([:\\a-zA-Z_\-0-9\.()]+)(""?)", 0, CommandLine)) // handle case where script name is not enclosed in quotes
|
||||
, CommandLine
|
||||
| project ScriptName=trim(@"""", ScriptName) , ScriptNameLength=strlen(ScriptName), CommandLine
|
||||
// extract remainder of commandline as script parameters:
|
||||
| project ScriptName, ScriptParams = iff(ScriptNameLength < strlen(CommandLine), substring(CommandLine, ScriptNameLength +1), "")
|
||||
| summarize by ScriptName, ScriptParams
|
|
@ -0,0 +1,41 @@
|
|||
id: 36abe031-962d-482e-8e1e-a556ed99d5a3
|
||||
name: Cscript script daily summary breakdown
|
||||
description: |
|
||||
'breakdown of scripts running in the environment'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Execution
|
||||
query: |
|
||||
|
||||
let timeframe = 1d;
|
||||
let ProcessCreationEvents=() {
|
||||
let processEvents=SecurityEvent
|
||||
| where EventID==4688
|
||||
| project EventTime=TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName,
|
||||
FileName=tostring(split(NewProcessName, '\\')[-1]), ProcessCommandLine = CommandLine,
|
||||
InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine="",InitiatingProcessParentFileName="";
|
||||
processEvents;
|
||||
};
|
||||
// Daily summary of cscript activity – extracting script name and parameters from commandline:
|
||||
ProcessCreationEvents
|
||||
| where EventTime >= ago(timeframe)
|
||||
| where FileName =~ "cscript.exe"
|
||||
// remove commandline switches
|
||||
| project EventTime, ComputerName, AccountName, removeSwitches = replace(@"/+[a-zA-Z0-9:]+", "", ProcessCommandLine)
|
||||
// remove the leading cscript.exe process name
|
||||
| project EventTime, ComputerName, AccountName, CommandLine = trim(@"[a-zA-Z0-9\\:""]*cscript(.exe)?("")?(\s)+", removeSwitches)
|
||||
// extract the script name:
|
||||
| project EventTime, ComputerName, AccountName,
|
||||
// handle case where script name is enclosed in " characters or is not enclosed in quotes
|
||||
ScriptName= iff(CommandLine startswith @"""",
|
||||
extract(@"([:\\a-zA-Z_\-\s0-9\.()]+)(""?)", 0, CommandLine),
|
||||
extract(@"([:\\a-zA-Z_\-0-9\.()]+)(""?)", 0, CommandLine)), CommandLine
|
||||
| project EventTime, ComputerName, AccountName, ScriptName=trim(@"""", ScriptName) , ScriptNameLength=strlen(ScriptName), CommandLine
|
||||
// extract remainder of commandline as script parameters:
|
||||
| project EventTime, ComputerName, AccountName, ScriptName, ScriptParams = iff(ScriptNameLength < strlen(CommandLine), substring(CommandLine, ScriptNameLength +1), "")
|
||||
| summarize min(EventTime), count() by ComputerName, AccountName, ScriptName, ScriptParams
|
||||
| order by count_ asc nulls last
|
||||
| extend timestamp = min_EventTime, HostCustomEntity = ComputerName, AccountCustomEntity = AccountName
|
|
@ -1,27 +0,0 @@
|
|||
// Name: Enumeration of users and groups
|
||||
//
|
||||
// Id: a1e993de-770a-4434-83e9-9e3b47a6e470
|
||||
//
|
||||
// Description: Finds attempts to list users or groups using the built-in Windows 'net' tool
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #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 != ''
|
||||
| summarize minTimeGenerated=min(TimeGenerated), maxTimeGenerated=max(TimeGenerated), count() by AccountName, Target, ProcessCommandLine, ComputerName
|
||||
| project minTimeGenerated, maxTimeGenerated, count_, AccountName, Target, ProcessCommandLine, ComputerName
|
||||
| sort by AccountName, Target
|
||||
| extend AccountCustomEntity = AccountName, HostCustomEntity = ComputerName
|
|
@ -0,0 +1,32 @@
|
|||
id: a1e993de-770a-4434-83e9-9e3b47a6e470
|
||||
name: Enumeration of users and groups
|
||||
description: |
|
||||
'Finds attempts to list users or groups using the built-in Windows 'net' tool '
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Discovery
|
||||
query: |
|
||||
|
||||
let timeframe = 1d;
|
||||
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 TimeGenerated >= ago(timeframe)
|
||||
| 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 != ''
|
||||
| summarize minTimeGenerated=min(TimeGenerated), maxTimeGenerated=max(TimeGenerated), count() by AccountName, Target, ProcessCommandLine, ComputerName
|
||||
| project minTimeGenerated, maxTimeGenerated, count_, AccountName, Target, ProcessCommandLine, ComputerName
|
||||
| sort by AccountName, Target
|
||||
| extend timestamp = minTimeGenerated, AccountCustomEntity = AccountName, HostCustomEntity = ComputerName
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
// Name: masquerading files.
|
||||
//
|
||||
// Id: 60304ebf-ebdd-4869-a702-e0216d90ab46
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #Execution, #DefenseEvasion
|
||||
//
|
||||
SecurityEvent
|
||||
| where NewProcessName endswith "\\svchost.exe"
|
||||
| where SubjectUserSid !in ("S-1-5-18", "S-1-5-19", "S-1-5-20")
|
||||
| where NewProcessName !contains ":\\Windows\\System32"
|
||||
| where NewProcessName !contains ":\\Windows\\Syswow64"
|
||||
| summarize minTimeGenerated=min(TimeGenerated), maxTimeGenerated=max(TimeGenerated), count() by Computer, SubjectUserName, NewProcessName, CommandLine, Account
|
||||
| project minTimeGenerated , maxTimeGenerated , count_ , Computer , SubjectUserName , NewProcessName , CommandLine, Account
|
||||
| extend HostCustomEntity = Computer, AccountCustomEntity = Account
|
|
@ -0,0 +1,27 @@
|
|||
id: 60304ebf-ebdd-4869-a702-e0216d90ab46
|
||||
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.'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Execution
|
||||
query: |
|
||||
|
||||
let timeframe = 1d;
|
||||
SecurityEvent
|
||||
| where TimeGenerated >= ago(timeframe)
|
||||
| where NewProcessName endswith "\\svchost.exe"
|
||||
| where SubjectUserSid !in ("S-1-5-18", "S-1-5-19", "S-1-5-20")
|
||||
| where NewProcessName !contains ":\\Windows\\System32"
|
||||
| where NewProcessName !contains ":\\Windows\\Syswow64"
|
||||
| summarize minTimeGenerated=min(TimeGenerated), maxTimeGenerated=max(TimeGenerated), count() by Computer, SubjectUserName, NewProcessName, CommandLine, Account
|
||||
| project minTimeGenerated , maxTimeGenerated , count_ , Computer , SubjectUserName , NewProcessName , CommandLine, Account
|
||||
| extend timestamp = minTimeGenerated, HostCustomEntity = Computer, AccountCustomEntity = Account
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
// Name: New processes observed in last 24 hours
|
||||
//
|
||||
// Id: 513e3a11-e1bb-4cfc-8af9-451da0407e6b
|
||||
//
|
||||
// Description: 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.
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #Execution
|
||||
//
|
||||
let ProcessCreationEvents=() {
|
||||
let processEvents=SecurityEvent
|
||||
| where EventID==4688
|
||||
| where TimeGenerated >= ago(14d)
|
||||
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName, FileName=tostring(split(NewProcessName, @'')[(-1)]), ProcessCommandLine = CommandLine, InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine='',InitiatingProcessParentFileName='';
|
||||
processEvents};
|
||||
ProcessCreationEvents
|
||||
| where TimeGenerated < ago(1d)
|
||||
| where TimeGenerated >= ago(14d)
|
||||
| summarize HostCount=dcount(ComputerName) by tostring(FileName)
|
||||
| join kind=rightanti (
|
||||
ProcessCreationEvents
|
||||
| where TimeGenerated >= ago(1d)
|
||||
| summarize HostCount=dcount(ComputerName) by tostring(FileName)
|
||||
) on FileName
|
||||
| project HostCount, FileName
|
|
@ -0,0 +1,32 @@
|
|||
id: 513e3a11-e1bb-4cfc-8af9-451da0407e6b
|
||||
name: New processes observed in last 24 hours
|
||||
description: |
|
||||
'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.'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Execution
|
||||
query: |
|
||||
|
||||
let starttime = 14d;
|
||||
let endtime = 1d;
|
||||
let ProcessCreationEvents=() {
|
||||
let processEvents=SecurityEvent
|
||||
| where EventID==4688
|
||||
| where TimeGenerated >= ago(starttime)
|
||||
| project TimeGenerated, ComputerName=Computer,AccountName=SubjectUserName, AccountDomain=SubjectDomainName, FileName=tostring(split(NewProcessName, @'')[(-1)]), ProcessCommandLine = CommandLine, InitiatingProcessFileName=ParentProcessName,InitiatingProcessCommandLine='',InitiatingProcessParentFileName='';
|
||||
processEvents};
|
||||
ProcessCreationEvents
|
||||
| where TimeGenerated >= ago(starttime) and TimeGenerated < ago(endtime)
|
||||
| summarize HostCount=dcount(ComputerName) by tostring(FileName)
|
||||
| join kind=rightanti (
|
||||
ProcessCreationEvents
|
||||
| where TimeGenerated >= ago(endtime)
|
||||
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), Computers = makeset(ComputerName) , HostCount=dcount(ComputerName) by tostring(FileName)
|
||||
) on FileName
|
||||
| project StartTimeUtc, Computers, HostCount, FileName
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
// Name: Summary of users created using uncommon & undocumented commandline switches
|
||||
//
|
||||
// Id: 5e76eaf9-79a7-448c-bace-28e5b53b8396
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #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
|
||||
| extend AccountCustomEntity = CreatedUser
|
|
@ -0,0 +1,37 @@
|
|||
id: 5e76eaf9-79a7-448c-bace-28e5b53b8396
|
||||
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)'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- CredentialAccess
|
||||
- LateralMovement
|
||||
relevantTechniques:
|
||||
- T1110
|
||||
query: |
|
||||
|
||||
let timeframe = 1d;
|
||||
SecurityEvent
|
||||
| where TimeGenerated >= ago(timeframe)
|
||||
| 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 StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), MachineCount=dcount(ComputerName) by CreatedUser, CreatedOnLocalMachine, InitiatingProcessFileName, FileName, ProcessCommandLine, InitiatingProcessCommandLine
|
||||
| extend timestamp = StartTimeUtc, AccountCustomEntity = CreatedUser
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
// Name: powershell downloads
|
||||
//
|
||||
// Id: d83f40fc-bbcc-4020-8d45-ad2d82355cb2
|
||||
//
|
||||
// Description: Finds PowerShell execution events that could involve a download
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #InitialAccess, #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
|
||||
| extend TimestampCustomEntity = TimeGenerated
|
||||
| extend HostCustomEntity = ComputerName
|
|
@ -0,0 +1,34 @@
|
|||
id: d83f40fc-bbcc-4020-8d45-ad2d82355cb2
|
||||
name: PowerShell downloads
|
||||
description: |
|
||||
'Finds PowerShell execution events that could involve a download'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Execution
|
||||
- CommandAndControl
|
||||
query: |
|
||||
|
||||
let timeframe = 1d;
|
||||
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 TimeGenerated >= ago(timeframe)
|
||||
| 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
|
||||
| extend timestamp = TimeGenerated, HostCustomEntity = ComputerName
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
// Name: new powershell scripts encoded on the commandline
|
||||
//
|
||||
// Id: 4e78daf1-8bba-4b5d-8a8b-c75fe9bbc2d9
|
||||
//
|
||||
// Description: Identify and decode new encoded powershell scripts this week versus previous fortnight
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #InitialAccess, #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};
|
||||
let encodedPSScripts =
|
||||
ProcessCreationEvents | where TimeGenerated >= ago(14d)
|
||||
| where FileName =~ "powershell.exe"
|
||||
| where ProcessCommandLine contains "-encodedCommand";
|
||||
encodedPSScripts
|
||||
| where TimeGenerated > ago(7d)
|
||||
| summarize count() by ProcessCommandLine
|
||||
| parse ProcessCommandLine with * "-EncodedCommand " encodedCommand
|
||||
| project decodedCommand=base64_decodestring(substring(encodedCommand, 0,
|
||||
strlen(encodedCommand) - (strlen(encodedCommand) %8))), encodedCommand
|
||||
| join kind=anti (encodedPSScripts
|
||||
| where TimeGenerated between(ago(21d)..ago(7d))
|
||||
| summarize count() by ProcessCommandLine
|
||||
| parse ProcessCommandLine with * "-EncodedCommand " encodedCommand
|
||||
| project decodedCommand=base64_decodestring(substring(encodedCommand, 0,
|
||||
strlen(encodedCommand) - (strlen(encodedCommand) %8))), encodedCommand
|
||||
) on encodedCommand, decodedCommand
|
|
@ -0,0 +1,43 @@
|
|||
id: 4e78daf1-8bba-4b5d-8a8b-c75fe9bbc2d9
|
||||
name: New PowerShell scripts encoded on the commandline
|
||||
description: |
|
||||
'Identify and decode new encoded powershell scripts this week versus previous 14 days'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Execution
|
||||
- CommandAndControl
|
||||
query: |
|
||||
|
||||
let starttime = 21d;
|
||||
let midtime = 14d;
|
||||
let endtime = 7d;
|
||||
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};
|
||||
let encodedPSScripts =
|
||||
ProcessCreationEvents
|
||||
| where TimeGenerated >= ago(midtime)
|
||||
| where FileName =~ "powershell.exe"
|
||||
| where ProcessCommandLine contains "-encodedCommand";
|
||||
encodedPSScripts
|
||||
| where TimeGenerated > ago(endtime)
|
||||
| summarize count() by ProcessCommandLine
|
||||
| parse ProcessCommandLine with * "-EncodedCommand " encodedCommand
|
||||
| project decodedCommand=base64_decodestring(substring(encodedCommand, 0,
|
||||
strlen(encodedCommand) - (strlen(encodedCommand) %8))), encodedCommand
|
||||
| join kind=anti (encodedPSScripts
|
||||
| where TimeGenerated between(ago(starttime)..ago(endtime))
|
||||
| summarize count() by ProcessCommandLine
|
||||
| parse ProcessCommandLine with * "-EncodedCommand " encodedCommand
|
||||
| project decodedCommand=base64_decodestring(substring(encodedCommand, 0,
|
||||
strlen(encodedCommand) - (strlen(encodedCommand) %8))), encodedCommand
|
||||
) on encodedCommand, decodedCommand
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
// Name: Uncommon processes - bottom 5%
|
||||
//
|
||||
// Id: 2ff4b10c-7056-4898-83fd-774104189fd5
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// DataSource: #SecurityEvent
|
||||
//
|
||||
// Tactics: #InitialAccess, #Execution, #Persistence, #PrivilegeEscalation, #CredentialAccess, #Discovery, #LateralMovement, #Collection, #Exfiltration, #CommandAndControl
|
||||
//
|
||||
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 @"\\TRA[0-9A-Fa-f]{3}\.tmp")
|
||||
| where not(NewProcessName matches regex @"\\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
|
||||
// normalize guids
|
||||
| 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 digits away
|
||||
| project TimeGenerated, FileName=replace(@'\d', 'n', FileName);
|
||||
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)
|
|
@ -0,0 +1,49 @@
|
|||
id: 2ff4b10c-7056-4898-83fd-774104189fd5
|
||||
name: Uncommon processes - bottom 5%
|
||||
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.'
|
||||
requiredDataConnectors:
|
||||
- connectorId: SecurityEvents
|
||||
dataTypes:
|
||||
- SecurityEvent
|
||||
tactics:
|
||||
- Execution
|
||||
query: |
|
||||
|
||||
let timeframe = 1d;
|
||||
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 @"\\TRA[0-9A-Fa-f]{3}\.tmp")
|
||||
| where not(NewProcessName matches regex @"\\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
|
||||
| where TimeGenerated >= ago(timeframe)
|
||||
// normalize guids
|
||||
| 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 digits away
|
||||
| project TimeGenerated, FileName=replace(@'\d', 'n', FileName);
|
||||
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)
|
||||
| extend timestamp = LastSeen
|
||||
|
Загрузка…
Ссылка в новой задаче