AWS S3 Unknown Requester


Description

Validates that proper IAM entities are accessing sensitive data buckets.

Query · python

from fnmatch import fnmatch

from panther_aws_helpers import aws_rule_context

# pylint: disable=line-too-long
BUCKET_ROLE_MAPPING = {
    "panther-bootstrap-processeddata-*": [
        "arn:aws:sts::*:assumed-role/panther-cloud-security-EventProcessorFunctionRole-*/panther-aws-event-processor",
        "arn:aws:sts::*:assumed-role/panther-log-analysis-AthenaApiFunctionRole-*/panther-athena-api",
        "arn:aws:sts::*:assumed-role/panther-log-analysis-RulesEngineFunctionRole-*/panther-rules-engine",
        "arn:aws:sts::*:assumed-role/panther-snowflake-logprocessing-role-*/snowflake",
        "arn:aws:sts::*:assumed-role/panther-data-replication-role-*/s3-replication",
    ]
}
# pylint: enable=line-too-long


def _unknown_requester_access(event):
    for bucket_pattern, role_patterns in BUCKET_ROLE_MAPPING.items():
        if not fnmatch(event.get("bucket", ""), bucket_pattern):
            continue
        if not any(
            (fnmatch(event.get("requester", ""), role_pattern) for role_pattern in role_patterns)
        ):
            return True
    return False


def rule(event):
    if event.get("errorcode"):
        return False

    return event.get("operation") == "REST.GET.OBJECT" and _unknown_requester_access(event)


def title(event):
    return (
        f"Unknown requester accessing data from S3 Bucket "
        f"[{event.get('bucket', '<UNKNOWN_BUCKET>')}]"
    )


def alert_context(event):
    return aws_rule_context(event)

Analyst notes

If the S3 access is not expected for this bucket, investigate the requester's other traffic.

Raw source AWS S3 Unknown Requester · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
Filename: aws_s3_unknown_requester_get_object.py
RuleID: "AWS.S3.ServerAccess.UnknownRequester"
DisplayName: "AWS S3 Unknown Requester"
DedupPeriodMinutes: 60 # 1 hour
Enabled: false
LogTypes:
  - AWS.S3ServerAccess
Tags:
  - AWS
  - Configuration Required
  - Security Control
  - Collection:Data From Cloud Storage Object
Reports:
  Panther:
    - Data Access
  MITRE ATT&CK:
    - TA0009:T1530
Severity: Low
Description: Validates that proper IAM entities are accessing sensitive data buckets.
Runbook: If the S3 access is not expected for this bucket, investigate the requester's other traffic.
Reference: https://docs.aws.amazon.com/AmazonS3/latest/userguide/walkthrough1.html
SummaryAttributes:
  - bucket
  - key
  - operation
  - userAgent
  - remoteip
  - requester
  - p_any_aws_arns
  - p_any_aws_account_ids
Tests:
  - Name: Expected Access
    ExpectedResult: false
    Log:
      {
        "bucketowner": "f16a9e81a6589df1c902c86f7982fd14a88787db",
        "bucket": "panther-bootstrap-processeddata-AF1341JAK",
        "time": "2020-02-14 00:53:48.000000000",
        "remoteip": "127.0.0.1",
        "requester": "arn:aws:sts::123456789012:assumed-role/panther-log-analysis-AthenaApiFunctionRole-1KK31J1/panther-athena-api",
        "requestid": "101B7403B9828743",
        "operation": "REST.GET.OBJECT",
        "key": "AWSLogs/o-wwwwwwgggg/234567890123/CloudTrail-Digest/ca-central-1/2020/02/14/234567890123_CloudTrail-Digest_ca-central-1_POrgTrail_us-east-1_20200214T001007Z.json.gz",
        "requesturi": "PUT /AWSLogs/o-wwwwwwgggg/234567890123/CloudTrail-Digest/ca-central-1/2020/02/14/234567890123_CloudTrail-Digest_ca-central-1_POrgTrail_us-east-1_20200214T001007Z.json.gz HTTP/1.1",
        "httpstatus": 200,
        "objectsize": 747,
        "totaltime": 110,
        "turnaroundtime": 20,
        "useragent": "aws-internal/3 aws-sdk-java/1.11.714 Linux/4.9.184-0.1.ac.235.83.329.metal1.x86_64 OpenJDK_64-Bit_Server_VM/25.242-b08 java/1.8.0_242 vendor/Oracle_Corporation",
        "hostid": "neRpT/AXRsS3LMBqq/wND59opwPRWWKn7F6evEhdbS99me5fyIXpVI/MMIn6ECgU1YZAqwuF8Bw=",
        "signatureversion": "SigV4",
        "ciphersuite": "ECDHE-RSA-AES128-SHA",
        "authenticationtype": "AuthHeader",
        "hostheader": "cloudtrail.s3.us-east-1.amazonaws.com",
        "tlsVersion": "TLSv1.2",
      }
  - Name: Unexpected Access
    ExpectedResult: true
    Log:
      {
        "bucketowner": "f16a9e81a6589df1c902c86f7982fd14a88787db",
        "bucket": "panther-bootstrap-processeddata-AF1341JAK",
        "time": "2020-02-14 00:53:48.000000000",
        "remoteip": "127.0.0.1",
        "requester": "arn:aws:iam::123456789012:user/jim-bob",
        "requestid": "101B7403B9828743",
        "operation": "REST.GET.OBJECT",
        "key": "AWSLogs/o-wwwwwwgggg/234567890123/CloudTrail-Digest/ca-central-1/2020/02/14/234567890123_CloudTrail-Digest_ca-central-1_POrgTrail_us-east-1_20200214T001007Z.json.gz",
        "requesturi": "PUT /AWSLogs/o-wwwwwwgggg/234567890123/CloudTrail-Digest/ca-central-1/2020/02/14/234567890123_CloudTrail-Digest_ca-central-1_POrgTrail_us-east-1_20200214T001007Z.json.gz HTTP/1.1",
        "httpstatus": 200,
        "objectsize": 747,
        "totaltime": 110,
        "turnaroundtime": 20,
        "useragent": "aws-internal/3 aws-sdk-java/1.11.714 Linux/4.9.184-0.1.ac.235.83.329.metal1.x86_64 OpenJDK_64-Bit_Server_VM/25.242-b08 java/1.8.0_242 vendor/Oracle_Corporation",
        "hostid": "neRpT/AXRsS3LMBqq/wND59opwPRWWKn7F6evEhdbS99me5fyIXpVI/MMIn6ECgU1YZAqwuF8Bw=",
        "signatureversion": "SigV4",
        "ciphersuite": "ECDHE-RSA-AES128-SHA",
        "authenticationtype": "AuthHeader",
        "hostheader": "cloudtrail.s3.us-east-1.amazonaws.com",
        "tlsVersion": "TLSv1.2",
      }
  - Name: Failed Request
    ExpectedResult: false
    Log:
      {
        "bucketowner": "f16a9e81a6589df1c902c86f7982fd14a88787db",
        "bucket": "panther-bootstrap-processeddata-AF1341JAK",
        "time": "2020-02-14 00:53:48.000000000",
        "errorcode": "AuthorizationHeaderMalformed",
        "remoteip": "127.0.0.1",
        "requestid": "101B7403B9828743",
        "operation": "REST.GET.OBJECT",
        "key": "AWSLogs/o-wwwwwwgggg/234567890123/CloudTrail-Digest/ca-central-1/2020/02/14/234567890123_CloudTrail-Digest_ca-central-1_POrgTrail_us-east-1_20200214T001007Z.json.gz",
        "requesturi": "PUT /AWSLogs/o-wwwwwwgggg/234567890123/CloudTrail-Digest/ca-central-1/2020/02/14/234567890123_CloudTrail-Digest_ca-central-1_POrgTrail_us-east-1_20200214T001007Z.json.gz HTTP/1.1",
        "httpstatus": 400,
        "objectsize": 747,
        "totaltime": 110,
        "turnaroundtime": 20,
        "useragent": "aws-internal/3 aws-sdk-java/1.11.714 Linux/4.9.184-0.1.ac.235.83.329.metal1.x86_64 OpenJDK_64-Bit_Server_VM/25.242-b08 java/1.8.0_242 vendor/Oracle_Corporation",
        "hostid": "neRpT/AXRsS3LMBqq/wND59opwPRWWKn7F6evEhdbS99me5fyIXpVI/MMIn6ECgU1YZAqwuF8Bw=",
        "signatureversion": "SigV4",
        "ciphersuite": "ECDHE-RSA-AES128-SHA",
        "authenticationtype": "AuthHeader",
        "hostheader": "cloudtrail.s3.us-east-1.amazonaws.com",
        "tlsVersion": "TLSv1.2",
      }
  - Name: Snowflake Request
    ExpectedResult: false
    Log:
      {
        "authenticationtype": "AuthHeader",
        "bucket": "panther-bootstrap-processeddata-AF1341JAK",
        "bucketowner": "f16a9e81a6589df1c902c86f7982fd14a88787db",
        "ciphersuite": "ECDHE-RSA-AES128-GCM-SHA256",
        "httpstatus": 200,
        "key": "logs/logdir/year%253D2020/month%253D09/day%253D30/hour%253D19/file.json.gz",
        "requesturi": "GET /logs/logdir/year%3D2020/month%3D09/day%3D30/hour%3D19/file.json.gz HTTP/1.1",
        "objectsize": 4063,
        "operation": "REST.GET.OBJECT",
        "remoteip": "127.0.0.1",
        "requester": "arn:aws:sts::123456789012:assumed-role/panther-snowflake-logprocessing-role-us-west-2/snowflake",
        "requestid": "101B7403B9828743",
        "signatureversion": "SigV4",
        "time": "2020-09-30 20:49:19.000000000",
        "tlsVersion": "TLSv1.2",
        "totaltime": 10,
        "turnaroundtime": 9,
        "useragent": "snowflake/1.0",
      }


# ------ paired body: aws_s3_unknown_requester_get_object.py ------

from fnmatch import fnmatch

from panther_aws_helpers import aws_rule_context

# pylint: disable=line-too-long
BUCKET_ROLE_MAPPING = {
    "panther-bootstrap-processeddata-*": [
        "arn:aws:sts::*:assumed-role/panther-cloud-security-EventProcessorFunctionRole-*/panther-aws-event-processor",
        "arn:aws:sts::*:assumed-role/panther-log-analysis-AthenaApiFunctionRole-*/panther-athena-api",
        "arn:aws:sts::*:assumed-role/panther-log-analysis-RulesEngineFunctionRole-*/panther-rules-engine",
        "arn:aws:sts::*:assumed-role/panther-snowflake-logprocessing-role-*/snowflake",
        "arn:aws:sts::*:assumed-role/panther-data-replication-role-*/s3-replication",
    ]
}
# pylint: enable=line-too-long


def _unknown_requester_access(event):
    for bucket_pattern, role_patterns in BUCKET_ROLE_MAPPING.items():
        if not fnmatch(event.get("bucket", ""), bucket_pattern):
            continue
        if not any(
            (fnmatch(event.get("requester", ""), role_pattern) for role_pattern in role_patterns)
        ):
            return True
    return False


def rule(event):
    if event.get("errorcode"):
        return False

    return event.get("operation") == "REST.GET.OBJECT" and _unknown_requester_access(event)


def title(event):
    return (
        f"Unknown requester accessing data from S3 Bucket "
        f"[{event.get('bucket', '<UNKNOWN_BUCKET>')}]"
    )


def alert_context(event):
    return aws_rule_context(event)

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.