Defender Track

Objective 4: Identify credential theft

Let's work our way backward through the hack by first focusing in on the ListBuckets call which can be found by using the jq query:

jq '.Records[]|select(.eventName=="ListBuckets")'
The response is:
{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "AROAJQMBDNUMIKLZKMF64:d190d14a-2404-45d6-9113-4eda22d7f2c7",
        "arn": "arn:aws:sts::653711331788:assumed-role/level3/d190d14a-2404-45d6-9113-4eda22d7f2c7",
        "accountId": "653711331788",
        "accessKeyId": "ASIAZQNB3KHGNXWXBSJS",
        "sessionContext": {
        "attributes": {
            "mfaAuthenticated": "false",
            "creationDate": "2018-11-28T22:31:59Z"
        },
        "sessionIssuer": {
            "type": "Role",
            "principalId": "AROAJQMBDNUMIKLZKMF64",
            "arn": "arn:aws:iam::653711331788:role/level3",
            "accountId": "653711331788",
            "userName": "level3"
        }
        }
    },
    "eventTime": "2018-11-28T23:09:28Z",
    "eventSource": "s3.amazonaws.com",
    "eventName": "ListBuckets",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "104.102.221.250",
    "userAgent": "[aws-cli/1.16.19 Python/2.7.10 Darwin/17.7.0 botocore/1.12.9]",
    "requestParameters": null,
    "responseElements": null,
    "requestID": "4698593B9338B27F",
    "eventID": "65e111a0-83ae-4ba8-9673-16291a804873",
    "eventType": "AwsApiCall",
    "recipientAccountId": "653711331788"
}

You'll notice the IP here is 104.102.221.250 which is not an Amazon owned IP. In this case it's the IP of nsa.gov. :) The only data I doctored in the logs was just to hide my home IP. We'll view this IP as the attacker's IP.

This call came from the role level3, so let's look at that:

aws --profile target_security iam get-role --role-name level3
Response:
{
    "Role": {
        "Description": "Allows ECS tasks to call AWS services on your behalf.",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "sts:AssumeRole",
                    "Principal": {
                        "Service": "ecs-tasks.amazonaws.com"
                    },
                    "Effect": "Allow",
                    "Sid": ""
                }
            ]
        },
        "MaxSessionDuration": 3600,
        "RoleId": "AROAJQMBDNUMIKLZKMF64",
        "CreateDate": "2018-11-23T17:55:27Z",
        "RoleName": "level3",
        "Path": "/",
        "Arn": "arn:aws:iam::653711331788:role/level3"
    }
}

You'll see this role is only supposed to be run by the ECS service, as the AssumeRolePolicyDocument is only allowing that Principal, but we just saw this IP clearly did not come from the AWS IP space (list of AWS IPs is here).

We don't have logs from the webserver that is running the ECS container, but we can assume from this one log event that it must have been hacked. Normally, you'd see the resource (the ECS in this case) having made AWS API calls from it's own IP that you could then compare against any new IPs it may have made. Using this concept is explained by Will Bengston in his talk Detecting Credential Compromise in AWS.

Next objective