Detection rules › Panther

Panther rules: brute

RuleSeverity
Brute Force By IPinformational
Brute Force By Userinformational

Brute Force By IP

#
Severity
informational
Log types
Asana.Audit, Atlassian.Audit, AWS.CloudTrail, Box.Event, GSuite.ActivityEvent, Okta.SystemLog, OneLogin.Events, OnePassword.SignInAttempt
Tags
DataModel, Credential Access:Brute Force
Reference
owasp.org
Source
github.com/panther-labs/panther-analysis

An actor user was denied login access more times than the configured threshold.

MITRE ATT&CK coverage

TacticTechniques
Credential Access

Telemetry coverage

Detection logic

from json import loads

import panther_event_type_helpers as event_type
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}: Login attempts from IP [{event.udm('source_ip')}] "
        "have exceeded the failed logins threshold"
    )
    if log_type == "AWS.CloudTrail":
        title_str += f" in [{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

Rule specification

AnalysisType: rule
Filename: brute_force_by_ip.py
RuleID: "Standard.BruteForceByIP"
DedupPeriodMinutes: 60
DisplayName: "Brute Force By IP"
Enabled: true
LogTypes:
  - Asana.Audit
  - Atlassian.Audit
  - AWS.CloudTrail
  - Box.Event
  - GSuite.ActivityEvent
  - Okta.SystemLog
  - OneLogin.Events
  - OnePassword.SignInAttempt
Severity: Info
Tags:
  - DataModel
  - Credential Access:Brute Force
Threshold: 20
Reports:
  MITRE ATT&CK:
    - TA0006:T1110
Description: An actor user was denied login access more times than the configured threshold.
Runbook: Analyze the IP they came from, and other actions taken before/after. Check if a user from this ip eventually authenticated successfully.
Reference: https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks
SummaryAttributes:
  - p_any_ip_addresses

Stages and Predicates

Fires on Asana.Audit, Atlassian.Audit, AWS.CloudTrail (and 5 more) events when the condition below holds.

Condition

  • event_type is failed_login
Alert cadence
alerts after 20 matches within 1h

Indicators

These rows show field, operator, and value matches.

Response runbook

Analyze the IP they came from, and other actions taken before/after. Check if a user from this ip eventually authenticated successfully.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "additionalEventData": {
    "LoginTo": "https://console.aws.amazon.com/console/",
    "MFAUsed": "No",
    "MobileVersion": "No"
  },
  "awsRegion": "us-east-1",
  "eventID": "1",
  "eventName": "ConsoleLogin",
  "eventSource": "signin.amazonaws.com",
  "eventTime": "2019-01-01T00:00:00Z",
  "eventType": "AwsConsoleSignIn",
  "eventVersion": "1.05",
  "p_event_time": "2021-06-04 09:59:53.650807",
  "p_log_type": "AWS.CloudTrail",
  "p_parse_time": "2021-06-04 10:02:33.650807",
  "recipientAccountId": "123456789012",
  "requestParameters": null,
  "responseElements": {
    "ConsoleLogin": "Failure"
  },
  "sourceIPAddress": "111.111.111.111",
  "userAgent": "Mozilla",
  "userIdentity": {
    "accountId": "123456789012",
    "arn": "arn:aws:iam::123456789012:user/tester",
    "principalId": "1111",
    "type": "IAMUser",
    "userName": "tester"
  }
}

Brute Force By User

#
Severity
informational
Log types
Asana.Audit, Atlassian.Audit, AWS.CloudTrail, Box.Event, GSuite.ActivityEvent, Okta.SystemLog, OneLogin.Events, OnePassword.SignInAttempt
Tags
DataModel, Credential Access:Brute Force
Reference
owasp.org
Source
github.com/panther-labs/panther-analysis

An actor user was denied login access more times than the configured threshold.

MITRE ATT&CK coverage

TacticTechniques
Credential Access

Telemetry coverage

Detection logic

from json import loads

import panther_event_type_helpers as event_type
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 [{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

Rule specification

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.ActivityEvent
  - 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

Stages and Predicates

Fires on Asana.Audit, Atlassian.Audit, AWS.CloudTrail (and 5 more) events when the condition below holds.

Condition

  • event_type is failed_login
Alert cadence
alerts after 20 matches within 1h

Indicators

These rows show field, operator, and value matches.

Response runbook

Analyze the user ID who failed to login, and other actions taken before/after. Check if this user eventually authenticated successfully.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "additionalEventData": {
    "LoginTo": "https://console.aws.amazon.com/console/",
    "MFAUsed": "No",
    "MobileVersion": "No"
  },
  "awsRegion": "us-east-1",
  "eventID": "1",
  "eventName": "ConsoleLogin",
  "eventSource": "signin.amazonaws.com",
  "eventTime": "2019-01-01T00:00:00Z",
  "eventType": "AwsConsoleSignIn",
  "eventVersion": "1.05",
  "p_event_time": "2021-06-04 09:59:53.650807",
  "p_log_type": "AWS.CloudTrail",
  "p_parse_time": "2021-06-04 10:02:33.650807",
  "recipientAccountId": "123456789012",
  "requestParameters": null,
  "responseElements": {
    "ConsoleLogin": "Failure"
  },
  "sourceIPAddress": "111.111.111.111",
  "userAgent": "Mozilla",
  "userIdentity": {
    "accountId": "123456789012",
    "arn": "arn:aws:iam::123456789012:user/tester",
    "principalId": "1111",
    "type": "IAMUser",
    "userName": "tester"
  }
}