Pivoting Clouds in AWS Organizations – Part 1: Leveraging Account Creation, Trusted Access, and Delegated Admin
Amazon Web Services (AWS) is a cloud solution that is used by a large variety of consumers from the single developer to the large corporate hierarchies that make up much of our day-to-day lives. While AWS certainly offers many developer solutions, its roughly 33% cloud share, combined with its vertical customer spread, makes it an attractive target for hackers. This has resulted in numerous presentations/articles regarding privilege escalation within a single AWS account.
While this is certainly instructional for smaller scale models or informal groupings of AWS accounts, a singular mindset with regard to AWS account takeovers might result in missed opportunities for larger corporate environments that specifically leverage AWS Organizations for account management and centralization. Identifying and exploiting a single misconfiguration or credential leak in the context of AWS Organizations could result in a blast radius that encompasses several, if not all, of the remaining AWS company assets.
This article uses an organization I built from my AWS penetration testing experience to both describe several key points of AWS Organizations theory and demonstrate exploitable opportunities in existing AWS solutions.
In part one of this two-part blog series, we’ll provide an “easy win” scenario and subsequently cover more involved pivoting opportunities with organization-integrated services. In part two, explore today’s AWS security features and tools for enumeration – including a Pacu module I built to assist in data collection.
Table of Contents
- AWS Accounts as a Security Boundary
- AWS Organizations Vocabulary
- Easy Win with Account Creation
- Trusted Access and Delegated Administration Review
- Leveraging IAM Access Analyzer Through Trusted Access
- Leveraging IAM Access Analyzer Through Delegated Administration
- IAM Identity Center (Successor to SSO) – Complete Control/Movement over
Member Account - Defense
- Conslusion
- Appendix: CLI Commands
AWS Accounts as a Security Boundary
To differentiate one AWS account from another, AWS assigns each account a unique 12-digit value called an “AWS Account Number” (ex. 000000000001). For notation’s sake (and my own sanity), I will be swapping out 12-digit numbers with letters after initial account introductions below. These AWS accounts present a container or security boundary from an information security standpoint.
Entities created by a service for an individual developer’s AWS account would not be accessible to other AWS accounts. While both Account A and Account B have the S3 service, making a “bucket” in the S3 service in Account A means that bucket entity exists only in Account A, and not Account B.
Of course, you can configure resources to be shared cross-account, but for this generalization we are focusing on the existence and core ownership of the resource. Since AWS Organizations groups a lot of accounts together in one central service, it presents several opportunities to tunnel through these security boundaries and get the associated account’s resources/data.
AWS Organizations Vocabulary
Before we dive into organizations, let’s run through some quick vocabulary. AWS Organizations is an AWS service where customers can create “organizations.” An organization is composed of one or more individual AWS accounts. In Figure 2 below, Account A is the account that created the organization and, as such, is called the management account.
The management account has administrator-like privileges over the entire organization. It can invite other AWS accounts, remove AWS accounts, delete an organization, attach policies, and more. In Figure 2, Account A invited Account B and Account C to join its organization. Accounts B and C are still separate AWS accounts, but by accepting Account A’s invitation their references appear in Account A’s organization entity. Once the invite is accepted, Accounts B and C become member accounts and, by default, have significantly less privileges than the management account.
A default member account can only view a few pieces of info associated with the management account. It cannot read other organization info, nor can it make changes in the organization. Default member accounts are so isolated that they do not have visibility into what other member accounts exist within the organization, only seeing themselves and the management account number.
Organizational Units (OUs) can be thought of as customer-created “folders” that you can use for arranging account resources. Root is a special entity that appears in every AWS Organization and can be thought of as functionally equivalent to an OU under which all accounts exist.
A diagram of our sample organization is given in Figure 2. Account ***********0 (Account A) is the account in charge of managing the overall organization, Account ***********9 (Account B) is a member account holding pre-production data, and Account ***********6 (Account C) is a member account holding production data. Account B has a highlighted overly permissive role with a trust access policy set to *. For steps to set up an organization, refer to the AWS user guide.
Finally, note that navigating to AWS Organizations in a management account like Account A provides a different UI layout than AWS Organizations in a member account like Account C (Figure 3 versus Figure 4). Noticeably the lefthand navigation bar is different. Because member accounts have significantly less permissions with regard to the organization, navigating to “AWS Accounts” or “Policies” in a default member account returns permission errors as expected. These differences can aid testers in determining if they have access to a management or member account during AWS pentesting.
Easy Win with Account Creation
In Figure 2, along with most of this 2-part series, we will assume the member accounts in the organization were all pre-existing accounts that were added through individual invites. However, we will take a quick detour from this assumption to look at the AWS account creation feature as this can return an easy early win. This is shown in Figure 5.
Account A can choose to create an AWS account when adding it to the organization (as opposed to inviting a pre-existing AWS account like Accounts B and C). When this is done, AWS creates a specific role with a default name of OrganizationAccount AccessRole in the newly created member account. We will denote this newly created member account as Account D.
If we were to view the newly created OrganizationAccountAccessRole role in Account D, we would see that the role has AdministratorAccess attached to it and trusts the management account, Account A.
Thus, if we compromise credentials for a user/role with the necessary privileges in Account A, we could go through each member account in the AWS Organization and try to assume this default role name. A successful attempt will return credentials as seen below (Figure 8) allowing one to pivot from, in this case, Account A to Account D essentially as an administrator.
Again, this is the “easy win” scenario where you can go from relative control in a management account to administrator control in a member account. However, this might not be as feasible if a default role is not present in member accounts, or you are lacking permissions, or the member account was invited instead of created. In these cases, trusted access and delegated administration would be the next two features to consider.
Trusted Access and Delegated Administration Review
A handful of AWS services have set up specific features or API subsets that integrate with AWS Organizations (ex. IAM Access Analyzer) allowing their functionality to expand from a single AWS account to the entire organization. These organization-integrated features are in what we might consider an “off” state by default.
Per AWS, trusted access is when you “enable a compatible AWS service to perform operations across all of the AWS accounts in your organization.” In other words, you can think of trusted access as the “on” switch for these feature integrations. You “trust” the specific integrated feature thereby giving it “trusted access” to the organization data and associated accounts. The exact mechanism by which the feature operations are then carried out might involve service-linked roles created in each relevant account, but we will not examine this too closely for the purpose of this article. Just know trusted access generally grants the feature access to the entire organization.
Figure 9 demonstrates an expected trusted access workflow. Account A “enables” trusted access for one of the predefined organization-supported features which can then access the necessary management/member account resources. From this point onwards, the ability to influence/access/change the associated member accounts is feature specific with Access Analyzer, for example, choosing to access and scan each member account in the organization for trust violations. Enabling a feature like IAM Access Analyzer from the management account means it is an enabled service.
Delegated administration is a status applied to member accounts and gives the targeted member account “read-only access to AWS Organizations service data.” This would allow a member to perform actions like listing AWS organization accounts which was previously blocked per the UI errors in Figure 4. Additionally, the management account is “delegating” permissions to the member account with regards to a specific organization-integrated feature, such that the member account now has the permissions to run the specific feature within their own account on the entire organization.
Delegated administration is illustrated by the blue lines in the diagram above (Figure 9). Account A would make Account C a delegated administrator specifically for IAM Access Analyzer, and Account C could now run IAM Access analyzer on the entire organization. Making a member account a delegated administrator for certain services like IAM Access Analyzer means Access Analyzer is a delegated service in Account C.
Trusted access and delegated administration are extremely feature-specific concepts and not every organization-integrated feature supports both trusted access and delegated administrators. Learn more about the services you can use with AWS Organizations here.
Leveraging IAM Access Analyzer through Trusted Access
Let’s assume we have compromised credentials for Account A. We could end this attack here but looking in AWS Organizations we would see the additional AWS Accounts B and C listed as member accounts. While we have no credentials or visibility into either member account, we can use our organization permissions from Account A to enable trusted access for a service (or use an already-enabled service). This will allow us to gather data on the member accounts.
IAM Access Analyzer reviews the roles in an AWS account and tells you if any role trust relationships reach outside a “trust zone.” For example, if you have a role in an AWS account that allows any other AWS account to assume it, that role would get flagged as violating the trust zone since “any AWS account” is a much larger scope than a single AWS account.
When integrated with AWS Organizations, the Access Analyzer associated trust zone (and as a byproduct, scan range) expands to the entire organization. By giving IAM Access Analyzer trusted access in Account A, we can let the Analyzer scan each member account in the organization and return a report that would include Account B’s vulnerable role.
Before we begin, let’s review each account’s IAM roles. Note we only have access to Account A info, but both role lists are provided here for transparency. Account B has the role with the trusted entity of * that we want to both discover and exploit as Account A.
Figures 10: Account A & Account B Starting IAM Roles Before Exploitation
As the attacker in Account A, navigate to “Services” in AWS Organizations and observe that the IAM Access Analyzer is disabled by default. While we could use the UI controls to enable the organization-integrated feature, we could also make use of the AWS Command Line Interface (CLI) using the leaked credentials.
Next, navigate to the IAM Access Analyzer feature within the IAM service and create an analyzer. Since Access Analyzer is now an enabled service, we can set the “Zone of trust” to the entire organization.
Figures 12: Creating an Access Analyzer
After a few minutes refresh the page and observe that the overly trusting role from Account B is listed as an active finding demonstrating an indirect avenue for collecting Account B data as an Account A entity.
To complete the POC, observe how the attacker in Account A can take the knowledge from the vulnerability scan (specifically the role ARN), and assume the role in Account B thus pivoting within the general organization.
While not critical to know for the attacker steps listed above, we can review both accounts again and note that a new service-created role was created and used in each member account per the organization-integrated feature: AWSServiceRoleForAccessAnalyzer.
Figures 15: Account A & Account B IAM Roles After Exploitation
Leveraging IAM Access Analyzer Through Delegated Administration
To demonstrate delegated administrator exploitation regarding Access Analyzer, we need to enable delegated administration in our current organization environment. To do so from Account A, navigate to Account A’s Access Analyzer feature, choose to add a delegated administrator, and enter Account C’s account number.
Assume that we have compromised credentials for Account C (as opposed to Account A). Also assume we have no starting knowledge regarding the organization. As Account C, we can navigate to the AWS Organizations service, and can conclude that we are probably a member account since the management account number does not match our compromised account number (under the Dashboard tab), and the general UI layout is not that of a management account.
However, unlike a default member account, the “AWS Accounts” tab now returns all AWS accounts in the organization instead of permission denied errors. Remember that one of the first things a delegated administrator gets is read-only rights to the organization. Thus, we can further hypothesize that we are not just a default member account, but a delegated administrator.
But delegated administrator for what? Since there is no centralized UI component in a member account that lists all the delegated services, we would need to browse to each organization-integrated feature in Account C (IAM Access Analyzer, S3 Storage Lens, etc.) where the UI will hopefully tell us if we are the delegated administrator for that feature.
This is very cumbersome, and we can leverage the CLI in the Appendix of this blog with our delegated administrator read-only rights to speed along the identification process as seen below. First, we call “list-delegated-administrators” to reconfirm our previous hypothesis that Account C is a delegated administrator. We can then list out all the delegated services in relation to ourselves by passing in our own account number to “list-delegated-services-for-account.” In this case, we can see that Access Analyzer is listed (access-analyzer.amazonaws.com) as the delegated service.
From here, finding the overly trusting role in Account B plays out much the same way as the trusted access example. We create an analyzer in Account C (now having the option to choose the entire organization due to the delegated administrator status), wait for the results, and identify the overly trusting role in Account B. Note that during setup, my first analyzer did not pick up the role immediately so deleting the old analyzer and making a new one seems to be a good debugging step.
While the previous example started from the perspective of a compromised management account, delegated administrations show how a member account can still leverage organization-integrated features to access/analyze/change member accounts in the overall organization.
IAM Identity Center (Successor to SSO) – Complete Control/Movement over Member Account
IAM Identity Center can be thought of as another “easy win” where one can authenticate to any select member account allowing for full account takeover. While this does support delegated administration, we will just focus on trusted access. Once again, we will assume that you, as an attacker, have compromised credentials for Account A and are now in complete control of the management account.
Navigate to the IAM Identity Center service and choose to “Enable” it. This is the equivalent of enabling trusted access, and listing enabled services now returns IAM Identity Center as “sso.amazonaws.com”.
Figures 20: Enabling the IAM Identity Center Service
Glancing over IAM Identity Center, we can see AWS Organizations is embedded within the service under “AWS accounts”, and that we have the option to create users with associated permission sets. A user entity can be used to sign into the AWS access portal URL, and a permission set says what one can do in terms of IAM privileges. To get into any member account in AWS Organizations, we will create a user with a one-time password (OTP), create a permission set allowing access to all actions/resources, attach the user and permission set to target member account, and subsequently authenticate as the user to get access to the member account.
Create a user as shown below in Figure 22. Note we will choose the option to “generate a one-time password.” Instead of getting an OTP, we could also choose to send an email to create the user.
At the end of the user creation workflow, we are given an OTP and a Sign-In link. Note this access portal URL is the same URL displayed on the main dashboards page of IAM Identity Center.
Next, create a permission set. Think of permission sets as wrappers for IAM policies. We can wrap items like AWS-managed/customer-managed/inline IAM policies in each permission set via the “Custom permission set” workflow. For simplicity’s sake, we will just choose a “Predefined permission set” that already includes the equivalent of the AdministratorAccess policy. While these permission sets encapsulate IAM policies, they are not the same entity and have their own ARN format.
Figures 24: Creating Permission Set Workflow
Now that we have our user and permission set, we can set up a user to log into any member account in our organization displayed in the “AWS accounts” item in the lefthand navigation bar.
Figures 25: Attaching a User/Permission Set to Account Workflow
Now that the user is assigned to the member account, navigate to the sign in URL from earlier and enter the username/OTP combination following the login prompts.
Figures 26: Authenticate as User Workflow
Observe that post-authentication returns a portal with links for accessing the member AWS account via the UI or direct credentials. Clicking on the UI option takes us into the AWS console for Account C. In the UI we can see we are the user with the AdministratorAccess permission set. Thus, we have turned our account takeover of one AWS account into two AWS accounts. We could also have done the exact same vector of attack for Account B allowing for a complete takeover of every AWS account in the organization.
Figures 27: Sign into Member Account as AdministratorAccess User
It is worth mentioning that one can configure the service to automatically email OTPs upon user creation via the CLI if that is desired to avoid UI interaction. However, the act of turning on this setting still requires access to the UI making the leveraging UI elements an apparent necessity. After setting up automated email OTPs, you can create the user and permission set via CLI, and immediately try to sign in via the sign-in URL with the username (not the user’s email). An email is then sent that is associated with the username containing the OTP in the email.
Defense
The scenarios above started with the prerequisite that the management or member account credentials had been compromised. Thus, the pivoting techniques listed above do not represent an inherent flaw in AWS itself, but represent potential vectors of attack if certain access is gained through leaked credentials, internal threats, etc. Users can perform several actions to help defend against attacker movement in their organizations including:
- Adhering to a principle of least privilege at the IAM level. Ideally users in the AWS environment should only have the permissions necessary to do their job. These granular controls mean If an account were compromised, the attacker might not be able to pivot any further into the environment.
- Adhering to a principle of least privilege at the service level. Ensure that organization-integrated features with trusted access or delegated administration are needed and used. Leaving organization-integrated features enabled when not needed introduces an unnecessary blast radius.
- Protect credentials, especially those for management accounts and delegated administrators. As seen above, these two positions grant access potentially to an entire organization, so the AWS keys should be protected and maintained.
- Ensure proper logging infrastructure is set up so Organization actions are properly documented and monitored.
The following AWS articles provide guidance pertaining to the points discussed above. Or connect with NetSPI to learn how an AWS penetration test can help you uncover areas of misconfiguration or weakness in your AWS environment.
- https://docs.aws.amazon.com/organizations/latest/userguide/orgs_best-practices_mgmt-acct.html
- https://docs.aws.amazon.com/organizations/latest/userguide/best-practices_member-acct.html
- https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html
- https://docs.aws.amazon.com/singlesignon/latest/userguide/delegated-admin.html
- https://docs.aws.amazon.com/organizations/latest/userguide/orgs_security_incident-response.html
Conclusion
This article covers conceptual knowledge and demonstrates actual mechanisms for pivoting within an AWS Organization. Note that the article only covered IAM Access Analyzer and IAM Identity Center, but there are many other organization-integrated features.
It is highly encouraged that if you are on an assessment without an easy AssumeRole into member accounts, and see an enabled organization feature, to review the specific feature documentation for possible pivoting techniques.
In the part two of this blog series, we will review one more organization-integrated feature, a recent Organization service update, and a tool I have created and pushed to Pacu to assist in enumerating all that was discussed above in one command.
Appendix: CLI Commands
Below is a summary of the important CLI commands that were used or leveraged through the UI. I have also included two examples of CLI workflows for Access Analyzer and Identity Center referenced above. As mentioned, Identity Center involves a mix of UI-only functionality and CLI commands unless the OTP email setting is otherwise configured by default.
# Base Organization Read APIs
aws organizations describe-organization aws organizations list-roots aws organizations list-accounts aws organizations list-aws-service-access-for-organization aws organizations list-delegated-administrators aws organizations list-delegated-services-for-account --account-id [account number] aws organizations list-organizational-units-for-parent –parent-id [OU/root ID]
# Base Organization Mutate APIs
aws organizations enable-aws-service-access –service-principal [principal designated URL] aws organizations register-delegated-administrator –account-id [account number] –service-principal [principal designated URL]
# Create Analyzer
└─$ aws accessanalyzer create-analyzer --analyzer-name "TestAnalyzer" --type "ORGANIZATION" --profile Orchestrator --region us-east-1 { "arn": "arn:aws:access-analyzer:us-east-1: [REDACTED]0:analyzer/TestAnalyzer" }
# List Access Analyzer Findings
└─$ aws accessanalyzer list-findings --analyzer-arn "arn:aws:access-analyzer:us-east-1: [REDACTED]0:analyzer/TestAnalyzer" --profile Orchestrator --region us-east-1 { "findings": [ { "id": "da8a421c-8d7f-47d7-b9aa-58ea3df45a6c", "principal": { "AWS": "*" }, "action": [ "sts:AssumeRole" ], "resource": "arn:aws:iam:: [REDACTED]6:role/RoleToListS3Stuff", "isPublic": true, "resourceType": "AWS::IAM::Role", "condition": {}, "createdAt": "2022-12-21T04:29:13.377000+00:00", "analyzedAt": "2022-12-21T04:29:13.377000+00:00", "updatedAt": "2022-12-21T04:29:13.377000+00:00", "status": "ACTIVE", "resourceOwnerAccount": "579735764396" } ] }
# Get Specific Analyzer Finding
└─$ aws accessanalyzer get-finding --analyzer-arn "arn:aws:access-analyzer:us-east-1: [REDACTED]0:analyzer/TestAnalyzer" --id "da8a421c-8d7f-47d7-b9aa-58ea3df45a6c" --profile Orchestrator --region us-east-1 { "finding": { "id": "da8a421c-8d7f-47d7-b9aa-58ea3df45a6c", "principal": { "AWS": "*" }, "action": [ "sts:AssumeRole" ], "resource": "arn:aws:iam::[REDACTED]6:role/RoleToListS3Stuff", "isPublic": true, "resourceType": "AWS::IAM::Role", "condition": {}, "createdAt": "2022-12-21T04:29:13.377000+00:00", "analyzedAt": "2022-12-21T04:29:13.377000+00:00", "updatedAt": "2022-12-21T04:29:13.377000+00:00", "status": "ACTIVE", "resourceOwnerAccount": "579735764396" } }
# IAM Access Analyzer Example Workflow
# Get instance ID
└─$ aws sso-admin list-instances --profile Orchestrator --region us-west-2 { "Instances": [ { "InstanceArn": "arn:aws:sso:::instance/ssoins-7907a1fb914efa94", "IdentityStoreId": "d-92676f572a" } ] }
# Create user. Note password is not returned via CLI and one needs to either get it from the UI via “Reset Password” on the new user or have the OTP auto-email setting configured.
└─$ aws identitystore create-user --profile Orchestrator --region us-west-2 --identity-store-id "d-92676f572a" --name "Formatted=FormattedValue,GivenName=GivenNameValue,FamilyName=FamilyNameValue" --user-name "Username" --display-name "TEST" --emails "Value=[REDACTED]@gmail.com,Type=Work,Primary=True" { "UserId": "d81153b0-9051-709f-f49e-b6d9ec91f892", "IdentityStoreId": "d-92676f572a" }
# Create Permission Set
└─$ aws sso-admin create-permission-set --name "PermissionSetOne" --instance-arn "arn:aws:sso:::instance/ssoins-7907a1fb914efa94" --session-duration "PT12H" --profile Orchestrator --region us-west-2 { "PermissionSet": { "Name": "PermissionSetOne", "PermissionSetArn": "arn:aws:sso:::permissionSet/ssoins-7907a1fb914efa94/ps-a8a74ca5fd800994", "CreatedDate": "2022-12-18T19:51:37.664000-05:00", "SessionDuration": "PT12H" } } └─$ aws sso-admin attach-managed-policy-to-permission-set --instance-arn "arn:aws:sso:::instance/ssoins-7907a1fb914efa94" --permission-set-arn "arn:aws:sso:::permissionSet/ssoins-7907a1fb914efa94/ps-a8a74ca5fd800994" --managed-policy-arn "arn:aws:iam::aws:policy/AdministratorAccess" --profile Orchestrator --region us-west-2 { "PermissionSet": { "Name": "PermissionSetOne", "PermissionSetArn": "arn:aws:sso:::permissionSet/ssoins-7907a1fb914efa94/ps-a8a74ca5fd800994", "CreatedDate": "2022-12-18T19:51:37.664000-05:00", "SessionDuration": "PT12H" } }
# Attach permission set and user to account. Check status of provision.
└─$ aws sso-admin create-account-assignment --instance-arn "arn:aws:sso:::instance/ssoins-7907a1fb914efa94" --target-id "[REDACTED]6" --target-type "AWS_ACCOUNT" --permission-set-arn "arn:aws:sso:::permissionSet/ssoins-7907a1fb914efa94/ps-a8a74ca5fd800994" --principal-type "USER" --principal-id "d81153b0-9051-709f-f49e-b6d9ec91f892" --profile Orchestrator --region us-west-2 { "AccountAssignmentCreationStatus": { "Status": "IN_PROGRESS", "RequestId": "c6f6afee-efd2-4cad-a52e-58d937184b52", "TargetId": "[REDACTED]6", "TargetType": "AWS_ACCOUNT", "PermissionSetArn": "arn:aws:sso:::permissionSet/ssoins-7907a1fb914efa94/ps-a8a74ca5fd800994", "PrincipalType": "USER", "PrincipalId": "d81153b0-9051-709f-f49e-b6d9ec91f892" } } └─$ aws sso-admin describe-account-assignment-creation-status --instance-arn "arn:aws:sso:::instance/ssoins-7907a1fb914efa94" --account-assignment-creation-request-id "c6f6afee-efd2-4cad-a52e-58d937184b52" --profile Orchestrator --region us-west-2 { "AccountAssignmentCreationStatus": { "Status": "SUCCEEDED", "RequestId": "c6f6afee-efd2-4cad-a52e-58d937184b52", "TargetId": "[REDACTED]6", "TargetType": "AWS_ACCOUNT", "PermissionSetArn": "arn:aws:sso:::permissionSet/ssoins-7907a1fb914efa94/ps-a8a74ca5fd800994", "PrincipalType": "USER", "PrincipalId": "d81153b0-9051-709f-f49e-b6d9ec91f892", "CreatedDate": "2022-12-18T19:57:22.335000-05:00" } }
Explore more blog posts
Part 1: Ready for Red Teaming? Intelligence-Driven Planning for Effective Scenarios
Take time for dedicated planning and evaluation ahead of red team testing to prepare your organisation for effective red team exercises.
The Strategic Value of Platformization for Proactive Security
Read about NetSPI’s latest Platform milestone, enabling continuous threat exposure management (CTEM) with consolidated proactive security solutions.
Backdooring Azure Automation Account Packages and Runtime Environments
Azure Automation Accounts can allow an attacker to persist in the associated packages that support runbooks. Learn how attackers can maintain access to an Automation Account.