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
andappstream_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.
Bypassing Cloudtrail
With the command
aws sts get-caller-identity --profile appstream_machine_role | jq .
, access to the rolearn:aws:iam::761675973624:role/test-appstream
is established, which is typically only accessible through appstream.amazonaws.com.
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:
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
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