From b1694e91b08a6744fffa38def1d262b65007ff33 Mon Sep 17 00:00:00 2001 From: Ben Airey Date: Thu, 19 Dec 2024 10:48:57 -0600 Subject: [PATCH] split Standard.BruteForceByIp into IP and Username versions --- packs/standard_ruleset.yml | 1 + rules/standard_rules/brute_force_by_ip.py | 3 +- rules/standard_rules/brute_force_by_user.py | 45 ++ rules/standard_rules/brute_force_by_user.yml | 448 +++++++++++++++++++ 4 files changed, 496 insertions(+), 1 deletion(-) create mode 100644 rules/standard_rules/brute_force_by_user.py create mode 100644 rules/standard_rules/brute_force_by_user.yml diff --git a/packs/standard_ruleset.yml b/packs/standard_ruleset.yml index 7df4bcea6..7304d4a2c 100644 --- a/packs/standard_ruleset.yml +++ b/packs/standard_ruleset.yml @@ -24,6 +24,7 @@ PackDefinition: # Standard Detections - Standard.AdminRoleAssigned - Standard.BruteForceByIP + - Standard.BruteForceByUser - Standard.ImpossibleTravel.Login - Standard.MFADisabled - Standard.NewAWSAccountCreated diff --git a/rules/standard_rules/brute_force_by_ip.py b/rules/standard_rules/brute_force_by_ip.py index 29de37ee2..9be2d0433 100644 --- a/rules/standard_rules/brute_force_by_ip.py +++ b/rules/standard_rules/brute_force_by_ip.py @@ -15,7 +15,8 @@ def title(event): # use unified data model field in title log_type = event.get("p_log_type") title_str = ( - f"{log_type}: User [{event.udm('actor_user')}] has exceeded the failed logins threshold" + f"{log_type}: Login attempts from IP [{event.udm('source_ip')}] " + "have exceeded the failed logins threshold" ) if log_type == "AWS.CloudTrail": title_str += f" in [{lookup_aws_account_name(event.get('recipientAccountId'))}]" diff --git a/rules/standard_rules/brute_force_by_user.py b/rules/standard_rules/brute_force_by_user.py new file mode 100644 index 000000000..29de37ee2 --- /dev/null +++ b/rules/standard_rules/brute_force_by_user.py @@ -0,0 +1,45 @@ +from json import loads + +import panther_event_type_helpers as event_type +from panther_aws_helpers import lookup_aws_account_name +from panther_base_helpers import add_parse_delay +from panther_ipinfo_helpers import PantherIPInfoException, geoinfo_from_ip + + +def rule(event): + # filter events on unified data model field + return event.udm("event_type") == event_type.FAILED_LOGIN + + +def title(event): + # use unified data model field in title + log_type = event.get("p_log_type") + title_str = ( + f"{log_type}: User [{event.udm('actor_user')}] has exceeded the failed logins threshold" + ) + if log_type == "AWS.CloudTrail": + title_str += f" in [{lookup_aws_account_name(event.get('recipientAccountId'))}]" + return title_str + + +def alert_context(event): + try: + geoinfo = geoinfo_from_ip(event=event, match_field=event.udm_path("source_ip")) + except PantherIPInfoException: + geoinfo = {} + if isinstance(geoinfo, str): + geoinfo = loads(geoinfo) + context = {} + context["geolocation"] = ( + f"{geoinfo.get('city')}, {geoinfo.get('region')} in " f"{geoinfo.get('country')}" + ) + context["ip"] = geoinfo.get("ip") + context["reverse_lookup"] = geoinfo.get("hostname", "No reverse lookup hostname") + context["ip_org"] = geoinfo.get("org", "No organization listed") + try: + context = add_parse_delay(event, context) + except TypeError: + pass + except AttributeError: + pass + return context diff --git a/rules/standard_rules/brute_force_by_user.yml b/rules/standard_rules/brute_force_by_user.yml new file mode 100644 index 000000000..5d012f5ff --- /dev/null +++ b/rules/standard_rules/brute_force_by_user.yml @@ -0,0 +1,448 @@ +AnalysisType: rule +Filename: brute_force_by_user.py +RuleID: "Standard.BruteForceByUser" +DisplayName: "Brute Force By User" +Enabled: true +LogTypes: + - Asana.Audit + - Atlassian.Audit + - AWS.CloudTrail + - Box.Event + - GSuite.Reports + - Okta.SystemLog + - OneLogin.Events + - OnePassword.SignInAttempt +Severity: Info +Reports: + MITRE ATT&CK: + - TA0006:T1110 +Description: An actor user was denied login access more times than the configured + threshold. +DedupPeriodMinutes: 60 +Threshold: 20 +Reference: https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks +Runbook: Analyze the user ID who failed to login, and other actions taken before/after. + Check if this user eventually authenticated successfully. +SummaryAttributes: + - p_any_usernames +Tags: + - DataModel + - Credential Access:Brute Force +Tests: + - Name: AWS.CloudTrail - Successful Login + ExpectedResult: false + Log: + { + "eventVersion": "1.05", + "userIdentity": + { + "type": "IAMUser", + "principalId": "1111", + "arn": "arn:aws:iam::123456789012:user/tester", + "accountId": "123456789012", + "userName": "testuser", + }, + "eventTime": "2019-01-01T00:00:00Z", + "eventSource": "signin.amazonaws.com", + "eventName": "ConsoleLogin", + "awsRegion": "us-east-1", + "sourceIPAddress": "111.111.111.111", + "userAgent": "Mozilla", + "requestParameters": null, + "responseElements": { "ConsoleLogin": "Success" }, + "additionalEventData": + { + "LoginTo": "https://console.aws.amazon.com/console/", + "MobileVersion": "No", + "MFAUsed": "No", + }, + "eventID": "1", + "eventType": "AwsConsoleSignIn", + "recipientAccountId": "123456789012", + "p_log_type": "AWS.CloudTrail", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: AWS.CloudTrail - Failed Login + ExpectedResult: true + Mocks: + - objectName: geoinfo_from_ip + returnValue: >- + { + "ip": "111.111.111.111", + "region": "UnitTestRegion", + "city": "UnitTestCityNew", + "country": "UnitTestCountry", + "hostname": "somedomain.com", + "org": "Some Org" + } + Log: + { + "eventVersion": "1.05", + "userIdentity": + { + "type": "IAMUser", + "principalId": "1111", + "arn": "arn:aws:iam::123456789012:user/tester", + "accountId": "123456789012", + "userName": "tester", + }, + "eventTime": "2019-01-01T00:00:00Z", + "eventSource": "signin.amazonaws.com", + "eventName": "ConsoleLogin", + "awsRegion": "us-east-1", + "sourceIPAddress": "111.111.111.111", + "userAgent": "Mozilla", + "requestParameters": null, + "responseElements": { "ConsoleLogin": "Failure" }, + "additionalEventData": + { + "LoginTo": "https://console.aws.amazon.com/console/", + "MobileVersion": "No", + "MFAUsed": "No", + }, + "eventID": "1", + "eventType": "AwsConsoleSignIn", + "recipientAccountId": "123456789012", + "p_log_type": "AWS.CloudTrail", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: Box - Regular Event + ExpectedResult: false + Log: + { + "type": "event", + "additional_details": '{"key": "value"}', + "created_by": + { + "id": "12345678", + "type": "user", + "login": "cat@example", + "name": "Bob Cat", + }, + "ip_address": "111.111.111.111", + "event_type": "DELETE", + "p_log_type": "Box.Event", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: Box - Login Failed + ExpectedResult: true + Mocks: + - objectName: geoinfo_from_ip + returnValue: >- + { + "ip": "111.111.111.111", + "region": "UnitTestRegion", + "city": "UnitTestCityNew", + "country": "UnitTestCountry", + "hostname": "somedomain.com", + "org": "Some Org" + } + Log: + { + "type": "event", + "additional_details": '{"key": "value"}', + "created_by": + { + "id": "12345678", + "type": "user", + "login": "cat@example", + "name": "Bob Cat", + }, + "event_type": "FAILED_LOGIN", + "source": { "id": "12345678", "type": "user", "name": "Bob Cat" }, + "ip_address": "111.111.111.111", + "p_log_type": "Box.Event", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: GSuite - Normal Login Event + ExpectedResult: false + Log: + { + "id": { "applicationName": "login" }, + "ipAddress": "111.111.111.111", + "events": [{ "type": "login", "name": "login_success" }], + "p_log_type": "GSuite.Reports", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: GSuite - Failed Login Event + ExpectedResult: true + Mocks: + - objectName: geoinfo_from_ip + returnValue: >- + { + "ip": "111.111.111.111", + "region": "UnitTestRegion", + "city": "UnitTestCityNew", + "country": "UnitTestCountry", + "hostname": "somedomain.com", + "org": "Some Org" + } + Log: + { + "actor": { "email": "bob@example.com" }, + "id": { "applicationName": "login" }, + "ipAddress": "111.111.111.111", + "events": [{ "type": "login", "name": "login_failure" }], + "p_log_type": "GSuite.Reports", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: Okta - Successful Login + ExpectedResult: false + Log: + { + "actor": + { + "alternateId": "admin", + "displayName": "unknown", + "id": "unknown", + "type": "User", + }, + "client": { "ipAddress": "111.111.111.111" }, + "eventType": "user.session.start", + "outcome": { "reason": "VERIFICATION_ERROR", "result": "SUCCESS" }, + "p_log_type": "Okta.SystemLog", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: Okta - Failed Login + ExpectedResult: true + Mocks: + - objectName: geoinfo_from_ip + returnValue: >- + { + "ip": "111.111.111.111", + "region": "UnitTestRegion", + "city": "UnitTestCityNew", + "country": "UnitTestCountry", + "hostname": "somedomain.com", + "org": "Some Org" + } + Log: + { + "actor": + { + "alternateId": "admin", + "displayName": "unknown", + "id": "unknown", + "type": "User", + }, + "client": { "ipAddress": "111.111.111.111" }, + "eventType": "user.session.start", + "outcome": { "reason": "VERIFICATION_ERROR", "result": "FAILURE" }, + "p_log_type": "Okta.SystemLog", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: OneLogin - Normal Login Event + ExpectedResult: false + Log: + { + "event_type_id": 8, + "actor_user_id": 123456, + "actor_user_name": "Bob Cat", + "user_id": 123456, + "user_name": "Bob Cat", + "ipaddr": "111.111.111.111", + "p_log_type": "OneLogin.Events", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: OneLogin - Failed Login Event + ExpectedResult: true + Mocks: + - objectName: geoinfo_from_ip + returnValue: >- + { + "ip": "111.111.111.111", + "region": "UnitTestRegion", + "city": "UnitTestCityNew", + "country": "UnitTestCountry", + "hostname": "somedomain.com", + "org": "Some Org" + } + Log: + { + "event_type_id": 6, + "actor_user_id": 123456, + "actor_user_name": "Bob Cat", + "user_id": 123456, + "user_name": "Bob Cat", + "ipaddr": "1.2.3.4", + "p_log_type": "OneLogin.Events", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: GCP - Non Login Event + ExpectedResult: false + Log: + { + "protoPayload": + { + "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog", + "serviceName": "cloudresourcemanager.googleapis.com", + "methodName": "SetIamPolicy", + "authenticationInfo": { "principalEmail": "bob@example.com" }, + "requestMetadata": { "callerIP": "111.111.111.111" }, + "serviceData": + { + "@type": "type.googleapis.com/google.iam.v1.logging.AuditData", + "policyDelta": + { + "bindingDeltas": + [ + { + "action": "ADD", + "member": "cat@example.com", + "role": "roles/resourcemanager.organizationAdmin", + }, + ], + }, + }, + }, + "p_log_type": "GCP.AuditLog", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + + - Name: Asana - Failed Login + ExpectedResult: true + Mocks: + - objectName: geoinfo_from_ip + returnValue: >- + { + "ip": "111.111.111.111", + "region": "UnitTestRegion", + "city": "UnitTestCityNew", + "country": "UnitTestCountry", + "hostname": "somedomain.com", + "org": "Some Org" + } + Log: + { + "actor": + { + "actor_type": "user", + "email": "homer@springfield.com", + "gid": "2222222", + "name": "Homer", + }, + "context": { "client_ip_address": "8.8.8.8", "context_type": "web" }, + "created_at": "2021-10-21T23:38:10.364Z", + "details": { "method": ["ONE_TIME_KEY"] }, + "event_category": "logins", + "event_type": "user_login_failed", + "gid": "222222222", + "resource": + { + "email": "homer@springfield.com", + "gid": "2222222", + "name": "homer", + "resource_type": "user", + }, + "p_log_type": "Asana.Audit", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: Asana - Normal Login + ExpectedResult: false + Log: + { + "actor": + { + "actor_type": "user", + "email": "homer@springfield.com", + "gid": "2222222", + "name": "Homer", + }, + "context": { "client_ip_address": "8.8.8.8", "context_type": "web" }, + "created_at": "2021-10-21T23:38:10.364Z", + "details": { "method": ["ONE_TIME_KEY"] }, + "event_category": "logins", + "event_type": "user_login_succeeded", + "gid": "222222222", + "resource": + { + "email": "homer@springfield.com", + "gid": "2222222", + "name": "homer", + "resource_type": "user", + }, + "p_log_type": "Asana.Audit", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + } + - Name: 1Password - Regular Login + ExpectedResult: false + Log: + { + "uuid": "1234", + "session_uuid": "5678", + "timestamp": "2021-12-03 19:52:52", + "category": "success", + "type": "credentials_ok", + "country": "US", + "target_user": + { + "email": "homer@springfield.gov", + "name": "Homer Simpson", + "uuid": "1234", + }, + "client": + { + "app_name": "1Password Browser Extension", + "app_version": "20184", + "ip_address": "1.1.1.1", + "os_name": "Solaris", + "os_version": "10", + "platform_name": "Chrome", + "platform_version": "96.0.4664.55", + }, + p_log_type: "OnePassword.SignInAttempt", + } + - Name: 1Password - Failed Login + ExpectedResult: true + Mocks: + - objectName: geoinfo_from_ip + returnValue: >- + { + "ip": "111.111.111.111", + "region": "UnitTestRegion", + "city": "UnitTestCityNew", + "country": "UnitTestCountry", + "hostname": "somedomain.com", + "org": "Some Org" + } + Log: + { + "uuid": "1234", + "session_uuid": "5678", + "timestamp": "2021-12-03 19:52:52", + "category": "credentials_failed", + "type": "password_secret_bad", + "country": "US", + "target_user": + { + "email": "homer@springfield.gov", + "name": "Homer Simpson", + "uuid": "1234", + }, + "client": + { + "app_name": "1Password Browser Extension", + "app_version": "20184", + "ip_address": "111.111.111.111", + "os_name": "Solaris", + "os_version": "10", + "platform_name": "Chrome", + "platform_version": "96.0.4664.55", + }, + "p_log_type": "OnePassword.SignInAttempt", + "p_parse_time": "2021-06-04 10:02:33.650807", + "p_event_time": "2021-06-04 09:59:53.650807", + }