Bypass Cloudtrail Detection using AWS Appstream

Introduction


In this blog, we're going to talk about how one can bypass cloudtrail detection with AWS AppStream. While AWS AppStream has been a game-changer in managing applications, it seems there might be a loophole that could possibly be exploited for evading CloudTrail detection. We'll delve into the nitty-gritty of this issue, exploring the roles and permissions that could potentially be manipulated to bypass detection.

What is Appstream 2.0 ?


AWS AppStream is a fully managed application streaming service from Amazon, allowing users to access and use desktop applications from any device, anywhere, through a web browser.

While deep diving into AWS AppStream, it's essential to understand the different roles that come into play when launching AppStream instances in resource accounts. These roles, managed by AppStream, are pivotal in facilitating backend service communication. The roles are as follows:

  • PhotonInstance Role: Identified in the "aws sts get-caller-identity" output, this role is crucial during the launch of AppStream instances in resource accounts.

  • Machine Role ( appstream_machine_role ): Created by the customer within their AWS account, it is vital to assign the correct permissions to this role and attach it to the AppStream fleet. This role is referred to as “test-appstream” in the blog.

  • AppStream Service Role ( AmazonAppStreamServiceAccess ): This role describes the native AWS resources in a customer's account and is used by the backend for instance provisioning, making it a requisite when utilizing the AppStream service.

It is noteworthy that AppStream does not document any CloudTrail data from end-users who are utilizing the instance.

  • The IAM roles in question are configured by the customer, and all role permissions are defined by the customer.

  • As AppStream processes the request from its end user to launch an EC2 instance for a corresponding user, the CloudTrail logs document AppStream by name.

  • As an attacker, you would need access to AWS Appstream instances

NOTE: AWS will soon update its documentation for enhanced clarity.

Understanding How Appstream Works?


  • When an end user logs into a Linux fleet, they are assigned a user named as2-streaming-user

  • This user has access to all applications that are installed on the fleet's image by the admins. Thus, using an image created from the image builder for the AppStream fleet grants default access to all its installed applications. It is important to note this that Access to files/folders and applications on an image is controlled by admins. While creating image, admin can choose to configure ACLs to prevent users from accessing such resources. as2-streaming-user is a non-privileged user.

  • By default, awscli is pre-installed.

  • Running the command aws sts get-caller-identity | jq . reveals that the AWS accountID is not the customer's account but rather AWS managed account.

  • Reviewing the role linked with the fleet, it's evident that only appstream.amazonaws.com can assume this role.

  • After checking the IAM Role(test-appstream), the trusted entity of the role was allowing only appstream.amazonaws.com to assume this role. As you can see currently we are running this fleet on an EC2 instance, and yet ec2.amazonaws.com is not mentioned under the trusted entity.

  • If IMDS was present(which actually is) and the IAM Role was directly attached to the instance profile corresponding to the EC2 instance, then ideally ec2.amazonaws.com should have been under the Trusted Entity

  • This means, this instance is running under the fleet of Appstream AWS Accounts whose source is appstream.amazonaws.com

  • This instance operates under the fleet of AppStream AWS accounts, sourced from appstream.amazonaws.com. However, it cannot assume the role directly; only the AppStream service can assume this role, subsequently making temporary credentials available within the context of the instance, i.e arn:aws:iam::761675973624:role/test-appstream.

  • But there is another way of assuming the role and fetching these credentials, essentially impersonating Appstream Service.

Understanding ~/.aws/config for appstream instances


  • Upon checking ~/.aws/config It reveals two unique profiles: appstream_machine_role and appstream_home_folder_role

  • If you look closely, there is an executable AppStreamRoleCredentialProvider which helps this instance to essentially assume a role(generate credentials) in the customer's AWS Account and perform necessary tasks.

[profile appstream_machine_role]
credential_process = /usr/local/appstream/credentials-provider/AppStreamRoleCredentialProvider --role=Machine

[profile appstream_home_folder_role]
credential_process = /usr/local/appstream/credentials-provider/AppStreamRoleCredentialProvider --role=S3HomeFolder

Bypassing Cloudtrail


  • With the command aws sts get-caller-identity --profile appstream_machine_role | jq ., access to the role arn:aws:iam::761675973624:role/test-appstream is established, which is typically only accessible through appstream.amazonaws.com.

{
  "Account": "761675973624",
  "UserId": "AROA3CV3NAP4BCIV7TASY:PhotonSession",
  "Arn": "arn:aws:sts::761675973624:assumed-role/test-appstream/PhotonSession"
}
  • By exploring further and executing aws sts get-caller-identity --profile appstream_home_folder_role, we see both roles have been assumed.

  • The Role Session Name always remains the same for all users who access appstream service PhotonSession -> appstream_machine_role and Appstream2.0 -> appstream_home_folder_role

  • Checking Cloudtrail we can also see some trails regarding this username as AppStream2.0 & PhotonSession. Notably, AWS services integrated with CloudTrail emit events when they are accessed using AWS credentials. In this case, as shown in the CloudTrail events, AppStream is accessing S3 and EC2 on behalf of customers using AmazonAppStreamServiceAccess service role or the fleet machine role. Even though machine role is used by customer applications (or users), since it is assumed by AppStream to make temporary credentials available on the instance, CloudTrail events are shown under AppStream.

  • CloudTrail logs sourceIP as appstream.amazonaws.com. Our objective is to bypass CloudTrail detection and utilize the keys generated by /usr/local/appstream/credentials-provider/AppStreamRoleCredentialProvider --role=Machine or by simply using the --profile appstream_machine_role with AWS CLI commands.

NOTE: The machine_role is provisioned to facilitate customer applications or users connecting to the fleet to access AWS resources seamlessly. It is important to note that the policies governing this role are managed by the customers, allowing for a tailored approach to accessing AWS resources.

  • Generating a FederateLink for console sign-in is equally straightforward:

/usr/local/appstream/credentials-provider/AppStreamRoleCredentialProvider --role=Machine
-> {machine_role_credentials}
python3 federation.py
  • This produces a federated link to access AWS Management Console, enabling access AWS Management console, enabling low privileges user to utilise IAM Role attached to the fleet.

  • Accessing the AWS management console through the federated link is seamless.

  • CloudTrail subsequently recorded the entries.

Testing out same hypothesis on AWS Lambda with service-roles


  • Let's create a simple python function on AWS Lambda with the following contents

import os
def lambda_handler(event, context):
    os.system("printenv")
  • We can extract the STS Credentials for the service role that is attached to the Lambda function via the env variables.

  • Upon configuring the Credentials on my local system, you can check the subsequent Cloudtrail API calls of these credentials which is clearly logging my source IP address for the API call "GetCallerIdentity".

Signoff notes

According to the mentioned method one can simply generate credentials using the internal executables built by AWS team and bypass sourceIP and userName detection on Cloudtrail. Few things to keep in mind

  • Customers are responsible for the Images that they wish to attach to the fleet.

  • "appstream_machine_role" is configurable by customers essentially meaning granting access to AWS Resources and Services is upto the customer.

  • Any usage of the credentials generated by "appstream_machine_role" or "AmazonAppstreamServiceAccess" either from your local machine or from the running fleet will be logged as appstream.amazonaws.com under sourceIP and PhotoSession/Appstream2.0 under userName

Thank You!

Saransh Rana

Infrastructure Security @ CRED

Last updated