Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

THREAT-424 Stratus AWS IAM Detections #1475

Merged
merged 4 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions correlation_rules/aws_create_admin_iam_user.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
AnalysisType: correlation_rule
RuleID: "AWS.Administrative.IAM.User.Created"
DisplayName: "AWS.Administrative.IAM.User.Created"
Enabled: true
Severity: High
Description: Identifies when an Administrative IAM user is creates. This could indicate a potential security breach.
Reference: https://stratus-red-team.cloud/attack-techniques/AWS/aws.persistence.iam-create-admin-user/
Reports:
MITRE ATT&CK:
- TA0006:T1078
Detection:
- Sequence:
- ID: CreateUser
RuleID: AWS.IAM.CreateUser
- ID: AttachAdminUserPolicy
RuleID: AWS.IAM.AttachAdminUserPolicy
Transitions:
- ID: CreateUser FOLLOWED BY AttachAdminUserPolicy
From: CreateUser
To: AttachAdminUserPolicy
WithinTimeFrameMinutes: 60
Match:
- On: p_alert_context.request_username
LookbackWindowMinutes: 2160
Schedule:
RateMinutes: 1440
TimeoutMinutes: 5
Tests:
- Name: User Created, Followed By Admin Policy Attachment
ExpectedResult: true
RuleOutputs:
- ID: CreateUser
Matches:
p_alert_context.request_username:
'new-user':
- "2024-06-01T10:00:01Z"
- ID: AttachAdminUserPolicy
Matches:
p_alert_context.request_username:
'new-user':
- "2024-06-01T11:00:01Z"
- Name: User Created, Not Followed By Admin Policy Attachment
ExpectedResult: false
RuleOutputs:
- ID: CreateUser
Matches:
p_alert_context.request_username:
'new-user':
- "2024-06-01T10:00:01Z"
- Name: Wrong match
ExpectedResult: false
RuleOutputs:
- ID: CreateUser
Matches:
p_alert_context.request_username:
'new-user':
- "2024-06-01T10:00:01Z"
- ID: AttachAdminUserPolicy
Matches:
p_alert_context.request_username:
'not-new-user':
- "2024-06-01T11:00:01Z"
49 changes: 49 additions & 0 deletions correlation_rules/aws_create_backdoor_admin_iam_role.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
AnalysisType: correlation_rule
RuleID: "AWS.Backdoor.Administrative.IAM.Role.Created"
DisplayName: "AWS Backdoor Administrative IAM Role Created"
Enabled: true
Severity: High
Description: Identifies when CreateRole and AttachAdminRolePolicy CloudTrail events occur in a short period of time. This sequence could indicate a potential security breach.
Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html
Reports:
MITRE ATT&CK:
- TA0007:T1078
Detection:
- Sequence:
- ID: CreateRole
RuleID: AWS.IAM.CreateRole
- ID: AttachAdminRolePolicy
RuleID: AWS.IAM.AttachAdminRolePolicy
Transitions:
- ID: CreateRole FOLLOWED BY AttachAdminRolePolicy
From: CreateRole
To: AttachAdminRolePolicy
WithinTimeFrameMinutes: 60
Match:
- On: p_alert_context.request_rolename
LookbackWindowMinutes: 2160
Schedule:
RateMinutes: 1440
TimeoutMinutes: 5
Tests:
- Name: Role Created, Followed By Policy Attachment
ExpectedResult: true
RuleOutputs:
- ID: CreateRole
Matches:
p_alert_context.request_rolename:
'new-role':
- "2024-06-01T10:00:01Z"
- ID: AttachAdminRolePolicy
Matches:
p_alert_context.request_rolename:
'new-role':
- "2024-06-01T10:30:01Z"
- Name: Role Created, Not Followed By Policy Attachment
ExpectedResult: false
RuleOutputs:
- ID: CreateRole
Matches:
p_alert_context.request_rolename:
'new-role':
- "2024-06-01T10:00:01Z"
8 changes: 7 additions & 1 deletion packs/aws.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ PackDefinition:
- AWS.CloudTrail.Password.Policy.Discovery
- AWS.Console.LoginWithoutMFA
- AWS.EC2.SecurityGroupModified
- AWS.IAM.BackdoorRole
- AWS.IAM.Backdoor.User.Keys
- AWS.IAM.CredentialsUpdated
- AWS.IAM.Entity.InlinePolicyDoesNotGrantNetworkAdminAccess
Expand All @@ -79,7 +80,6 @@ PackDefinition:
- AWS.PasswordPolicy.PasswordReuse
- AWS.Potentially.Stolen.Service.Role.Scheduled
- AWS.Suspicious.SAML.Activity
- AWS.User.Login.Profile.Modified
# General Policies and Rules
- Amazon.EKS.Audit.Multiple403
- Amazon.EKS.Audit.SystemNamespaceFromPublicIP
Expand Down Expand Up @@ -188,6 +188,8 @@ PackDefinition:
- VPC.DNS.Tunneling
- VPCFlow.Port.Scanning
# Correlation Rules
- AWS.Administrative.IAM.User.Created
- AWS.Backdoor.Administrative.IAM.Role.Created
- AWS.Privilege.Escalation.Via.User.Compromise
- AWS.CloudTrail.SES.SESEnumeration
- AWS.SSO.Access.Token.Retrieved.by.Unauthenticated.IP
Expand All @@ -198,6 +200,10 @@ PackDefinition:
- AWS.CloudTrail.UserAccessKeyAuth
- AWS.CloudTrail.LoginProfileCreatedOrModified
- AWS.Console.Login
- AWS.IAM.AttachAdminRolePolicy
- AWS.IAM.AttachAdminUserPolicy
- AWS.IAM.CreateRole
- AWS.IAM.CreateUser
- AWS.CloudTrail.SES.CheckSESSendingEnabled
- AWS.CloudTrail.SES.CheckSendQuota
- AWS.CloudTrail.SES.ListIdentities
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
from panther_aws_helpers import aws_rule_context
from panther_aws_helpers import aws_cloudtrail_success, aws_rule_context

PROFILE_EVENTS = {
"UpdateLoginProfile",
"CreateLoginProfile",
"DeleteLoginProfile",
}


def rule(event):
# Only look for successes
if event.get("errorCode") or event.get("errorMessage"):
if not aws_cloudtrail_success(event):
return False

# Check when someone other than the user themselves creates or modifies a login profile
# with no password reset needed
return (
event.get("eventSource", "") == "iam.amazonaws.com"
and event.get("eventName", "") in PROFILE_EVENTS
and not event.deep_get("requestParameters", "passwordResetRequired", default=False)
and not event.deep_get("userIdentity", "arn", default="").endswith(
f"/{event.deep_get('requestParameters', 'userName', default='')}"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,74 +20,74 @@ Tests:
- Name: ChangeOwnPassword
ExpectedResult: false
Log:
awsRegion: us-east-1
eventCategory: Management
eventID: "1234"
eventName: UpdateLoginProfile
eventSource: iam.amazonaws.com
eventTime: "2022-09-15 13:45:24"
eventType: AwsApiCall
eventVersion: "1.08"
managementEvent: true
readOnly: false
recipientAccountId: "987654321"
requestParameters:
passwordResetRequired: false
userName: alice
sessionCredentialFromConsole: true
sourceIPAddress: AWS Internal
userAgent: AWS Internal
userIdentity:
accessKeyId: ABC1234
accountId: "987654321"
arn: arn:aws:sts::98765432:assumed-role/IAM/alice
principalId: ABCDE:alice
sessionContext:
attributes:
creationDate: "2022-09-15T13:36:47Z"
mfaAuthenticated: "true"
sessionIssuer:
accountId: "987654321"
arn: arn:aws:iam::9876432:role/IAM
principalId: 1234ABC
type: Role
userName: IAM
webIdFederationData: {}
type: AssumedRole
{ "awsRegion": "us-east-1",
"eventCategory": "Management",
"eventID": "1234",
"eventName": "UpdateLoginProfile",
"eventSource": "iam.amazonaws.com",
"eventTime": "2022-09-15 13:45:24",
"eventType": "AwsApiCall",
"eventVersion": "1.08",
"managementEvent": true,
"readOnly": false,
"recipientAccountId": "987654321",
"requestParameters":
{ "passwordResetRequired": false,
"userName": "alice" },
"sessionCredentialFromConsole": true,
"sourceIPAddress": "AWS Internal",
"userAgent": "AWS Internal",
"userIdentity":
{ "accessKeyId": "ABC1234",
"accountId": "987654321",
"arn": "arn:aws:sts::98765432:assumed-role/IAM/alice",
"principalId": "ABCDE:alice",
"sessionContext":
{ "attributes":
{ "creationDate": "2022-09-15T13:36:47Z",
"mfaAuthenticated": "true" },
"sessionIssuer":
{ "accountId": "987654321",
"arn": "arn:aws:iam::9876432:role/IAM",
"principalId": "1234ABC",
"type": "Role",
"userName": "IAM" },
"webIdFederationData": { } },
"type": "AssumedRole" } }
- Name: User changed password for other
ExpectedResult: true
Log:
awsRegion: us-east-1
eventCategory: Management
eventID: "1234"
eventName: UpdateLoginProfile
eventSource: iam.amazonaws.com
eventTime: "2022-09-15 13:45:24"
eventType: AwsApiCall
eventVersion: "1.08"
managementEvent: true
readOnly: false
recipientAccountId: "987654321"
requestParameters:
passwordResetRequired: false
userName: bob
sessionCredentialFromConsole: true
sourceIPAddress: AWS Internal
userAgent: AWS Internal
userIdentity:
accessKeyId: ABC1234
accountId: "987654321"
arn: arn:aws:sts::98765432:assumed-role/IAM/alice
principalId: ABCDE:alice
sessionContext:
attributes:
creationDate: "2022-09-15T13:36:47Z"
mfaAuthenticated: "true"
sessionIssuer:
accountId: "987654321"
arn: arn:aws:iam::9876432:role/IAM
principalId: 1234ABC
type: Role
userName: IAM
webIdFederationData: {}
type: AssumedRole
{ "awsRegion": "us-east-1",
"eventCategory": "Management",
"eventID": "1234",
"eventName": "UpdateLoginProfile",
"eventSource": "iam.amazonaws.com",
"eventTime": "2022-09-15 13:45:24",
"eventType": "AwsApiCall",
"eventVersion": "1.08",
"managementEvent": true,
"readOnly": false,
"recipientAccountId": "987654321",
"requestParameters":
{ "passwordResetRequired": false,
"userName": "bob" },
"sessionCredentialFromConsole": true,
"sourceIPAddress": "AWS Internal",
"userAgent": "AWS Internal",
"userIdentity":
{ "accessKeyId": "ABC1234",
"accountId": "987654321",
"arn": "arn:aws:sts::98765432:assumed-role/IAM/alice",
"principalId": "ABCDE:alice",
"sessionContext":
{ "attributes":
{ "creationDate": "2022-09-15T13:36:47Z",
"mfaAuthenticated": "true" },
"sessionIssuer":
{ "accountId": "987654321",
"arn": "arn:aws:iam::9876432:role/IAM",
"principalId": "1234ABC",
"type": "Role",
"userName": "IAM" },
"webIdFederationData": { } },
"type": "AssumedRole" } }
18 changes: 18 additions & 0 deletions rules/aws_cloudtrail_rules/aws_iam_attach_admin_role_policy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from panther_aws_helpers import aws_cloudtrail_success, aws_rule_context


def rule(event):
if not aws_cloudtrail_success(event) or event.get("eventName") != "AttachRolePolicy":
return False

policy = event.deep_get("requestParameters", "policyArn", default="POLICY_NOT_FOUND")

return policy.endswith("AdministratorAccess")


def alert_context(event):
context = aws_rule_context(event)
context["request_rolename"] = event.deep_get(
"requestParameters", "roleName", default="ROLENAME_NOT_FOUND"
)
return context
Loading
Loading