# 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.&#x20;

### What is Appstream 2.0 ?

***

[AWS AppStream](https://docs.aws.amazon.com/appstream2/) 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.**&#x20;

* The IAM roles in question are configured by the customer, and all role permissions are defined by the customer.&#x20;
* 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.&#x20;

<figure><img src="https://4115596560-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDhPh78z8rRkePKiZK44f%2Fuploads%2FFGqcWzv5Wqf4DxdPBXfD%2FScreenshot%202023-07-27%20at%207.40.55%20PM.png?alt=media&#x26;token=bd2de134-1009-4d90-bf65-df67c895d0ca" alt=""><figcaption><p>appstream.amazonaws.com</p></figcaption></figure>

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

<figure><img src="https://4115596560-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDhPh78z8rRkePKiZK44f%2Fuploads%2FnLQoZu9DtxYlGXhXarm7%2FScreenshot%202023-07-27%20at%207.45.49%20PM.png?alt=media&#x26;token=d9cf217e-6a9a-4200-9604-eeb0efad1a60" alt=""><figcaption><p>IAM Role attached to the fleet</p></figcaption></figure>

* 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.&#x20;

<figure><img src="https://4115596560-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDhPh78z8rRkePKiZK44f%2Fuploads%2FfB5IhKxpnVYSQsfRL3nb%2FScreenshot%202023-07-27%20at%207.47.00%20PM.png?alt=media&#x26;token=00484649-987a-460f-ad7d-9550f1d70903" alt=""><figcaption><p>IAM Role's Trust Relationship</p></figcaption></figure>

* 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.**&#x20;

### 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.

```json
[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&#x20;

***

* 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**.

```json
{
  "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.

<figure><img src="https://4115596560-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDhPh78z8rRkePKiZK44f%2Fuploads%2FAR9GqmjR0sLoYfIQvgam%2FScreenshot%202023-07-27%20at%208.08.04%20PM.png?alt=media&#x26;token=e4158535-5db3-4766-8505-ff639a9ad112" alt=""><figcaption><p>Assuming both profile roles</p></figcaption></figure>

* 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.

<figure><img src="https://4115596560-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDhPh78z8rRkePKiZK44f%2Fuploads%2FilZEADnJR635f4v56f72%2FScreenshot%202023-07-27%20at%208.10.37%20PM.png?alt=media&#x26;token=7de9bfef-5a01-424b-a29a-45c363324876" alt=""><figcaption><p>Cloudtrail logging user activity as Appstream2.0</p></figcaption></figure>

<figure><img src="https://4115596560-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDhPh78z8rRkePKiZK44f%2Fuploads%2Fl6NwXfmRwKr4qSofzXau%2FScreenshot%202023-07-27%20at%208.11.36%20PM.png?alt=media&#x26;token=0a04e7c6-4f29-4b43-ae03-452cfe6dff2d" alt=""><figcaption><p>Cloudtrail logging userIP as appstream.amazonaws.com</p></figcaption></figure>

* 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](https://github.com/groovyBugify/aws-federated-login) for console sign-in is equally straightforward:

```bash
/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.

<figure><img src="https://4115596560-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDhPh78z8rRkePKiZK44f%2Fuploads%2F9ejMWBc5z86bHJ4XRgbP%2FScreenshot%202023-07-28%20at%2012.21.10%20AM.png?alt=media&#x26;token=7a94a403-df04-41b0-b227-352c2d3ca2e6" alt=""><figcaption><p>Generating Federeated Link for Console Access</p></figcaption></figure>

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

<figure><img src="https://4115596560-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDhPh78z8rRkePKiZK44f%2Fuploads%2F3FtFTgLyFYT8Zr8lWLoD%2FScreenshot%202023-07-28%20at%2012.22.36%20AM.png?alt=media&#x26;token=47cf080b-4064-41e4-acff-964edb3b58df" alt=""><figcaption><p>Console access via "appstream-machine-role"</p></figcaption></figure>

* CloudTrail subsequently recorded the entries.

<figure><img src="https://4115596560-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDhPh78z8rRkePKiZK44f%2Fuploads%2Fl6NwXfmRwKr4qSofzXau%2FScreenshot%202023-07-27%20at%208.11.36%20PM.png?alt=media&#x26;token=0a04e7c6-4f29-4b43-ae03-452cfe6dff2d" alt=""><figcaption><p>event history for federated link access</p></figcaption></figure>

### Testing out same hypothesis on AWS Lambda with service-roles

***

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

```python
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.

<figure><img src="https://4115596560-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDhPh78z8rRkePKiZK44f%2Fuploads%2F20Cm8Ywn8a0FVoX4qB6j%2FScreenshot%202023-09-09%20at%204.02.18%20PM.png?alt=media&#x26;token=9d25438a-e292-45cd-b5bc-2ba0c748884f" alt=""><figcaption><p>exporting AWS Lambda's credentials to local</p></figcaption></figure>

* 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**".

<figure><img src="https://4115596560-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDhPh78z8rRkePKiZK44f%2Fuploads%2FxTwt3ivDlBswJsJRsd1X%2FScreenshot%202023-09-09%20at%204.16.55%20PM.png?alt=media&#x26;token=d0996e65-af81-467a-ad7b-6fa0e289d980" alt=""><figcaption><p>cloudtrail logging my IP address after running "GetCallerIdentity"</p></figcaption></figure>

### 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.&#x20;
* "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**
