In our previous two posts, Access and Data Flows and Data Backups and Encryption, we discussed security best practices to implement least-privileged access on Redshift and reduce the static risk associated with your sensitive data.
In today’s post we’ll show you how an attacker can exploit security risks to achieve lateral movement and privilege escalation. This allows the threat actor to leverage weak permissions and reach services and data sources they didn’t have access to initially.
What Is an Attack Vector?
An attack vector is the path that an attacker takes along the cyber kill chain to fulfill their mission. The cyber kill chain is a common way to split the attack into stages. It helps in understanding attacks and how to prevent them.
IAM Role Association
IAM role association allows Redshift to perform strong capabilities like copy, unload, query and analyze data from external sources. Along with those options, the IAM role carries a risk of exposing sensitive data.
We have observed many cases where overly permissive roles are attached to Redshift clusters, exposing sensitive data assets and their content to anyone with basic privileges.
Redshift Built-In Role
In the “create cluster” page, AWS allows you to create the default role for the Redshift cluster. The default role contains incredibly powerful permissions, with the attached policy “AmazonRedshiftAllCommandsFullAccess”.
The “AmazonRedshiftAllCommandsFullAccess” is a powerful policy containing excessive privileges that can lead to privilege escalation and lateral movement, even when created with the “No addition S3 bucket” option. We’ll show what risks can arise by allowing this policy later.
Next, we will demonstrate how an attacker who gained access to a very basic principal can use this default policy and perform S3 and Glue operations, invoke Lambdas, access Kinesis, fetch secrets to connect to RDS, Athena and Hive Metastore - all this when only given privileges to create a cluster (“redshift:CreateCluster”).
The following flow diagram shows the possible attack paths:
Basic AWS Principal
For the demo, we’re using a basic AWS principal with a policy attached that allows:
‘redshift:CreateCluster’, ‘redshift:DescribeClusters’, ‘iam:PassRole’, ‘ec2:Describe*’
Pro Tip
It’s recommended to know exactly which AWS principals have the permissions above, as it can potentially lead to unexpected access to other services.
Attackers that gain access to AWS with the above low-privileged principal can create a redshift cluster:
Performing Reconnaissance with the COPY Command
The COPY command allows the Redshift cluster to load data from external sources like S3, DynamoDB, EMR and EC2. The following flow diagram shows the possible attack path when using the COPY command:
In this section we will focus on the S3 bucket. The default role contains the following permissions, which eventually allow an attacker to “list”, “create”, “delete”, and “get objects” from buckets containing “redshift” in their name:
With access to the newly created redshift cluster, it is necessary to traverse over all the files in the S3 bucket to choose the desired files to exfiltrate. The permissions in the default role give the attacker the ability to do so.
By using the COPY command with <bucket name> instead of <file name>, an attacker can perform reconnaissance on the bucket to extract all the files in it:
To make Redshift ignore encoding and length errors the attacker can use the ‘TRUNCATECOLUMNS’ and ‘encoding UTF16BE’ properties.
By querying the “STL_LOAD_COMMITS” table, the attacker can find a list of all the filenames in the bucket:
Using the COPY command, they can list all the files in that bucket.
If an attacker tries to list all files in the bucket with their basic AWS principal, and not from Redshift, they will result with an “Access Denied” error:
Now that the attacker has the list of files in the bucket it is possible to exfiltrate them one by one with the correct encoding.
Structured Data Exfiltration with COPY Command
Loading the “employee.csv” file from the S3 bucket above:
Once the data is loaded, the attacker can query the ‘exfil’ table to get the data:
If the attacker will try to download the file with the low-privilege user, the command will result with an error:
Unstructured Data Exfiltration with COPY Command
Next, the attacker can also exfiltrate unstructured data like a pdf file. To do so, they can add some properties like ‘ACCEPTINVCHARS’, ‘BLANKSASNULL’, ‘IGNOREBLANKLINES’ to make the COPY command succeed:
The attacker can query the output table to get the data:
To make this output human readable, the attacker can copy the content and save it as a pdf file.
Pro Tip
It’s possible to detect suspicious usages of the COPY command by continuously monitoring the "STL_LOAD_ERRORS" and "STL_LOAD_COMMITS” tables.
Privilege Escalation Using the CREATE EXTERNAL SCHEMA Command
Using the CREATE EXTERNAL SCHEMA command, which allows querying from external sources, an attacker can escalate privileges and access external data services like Glue, Athena, Kinesis, RDS and Hive.
The following flow diagram shows the possible attack paths:
To understand how it’s possible, let's look at some of the privileges of the default role:
ListSecrets & GetSecretValue allow users in Redshift to connect to remote sources like RDS, Athena and Hive Metastore. The Redshift cluster gets the secret from the Secret Manager and opens a connection to the external service.
Redshift’s default role has interesting permissions for Glue as well. Glue has many usages, especially as an ETL pipe to move data from and to multiple sources (S3, Kinesis or Kafka). The permissions in the default policy:
It means that the Redshift cluster has permission to create and drop databases, get or delete tables in Glue, and more.
The default role allows performing actions on S3 buckets containing “redshift” in their name, but since Glue is not restricted by that policy, an attacker can leverage the Glue service to bypass name restriction to reach other S3 buckets that don’t contain the string “redshift” in their name.
The following flow diagram shows the possible attack paths:
In this case Glue database “attack-redshift” with the table “lake” that maps to S3 bucket called “ofir-data-lake”:
Attackers can access Glue objects from Redshift with the following command:
At this point, the attacker managed to access the S3 bucket files that weren’t accessible before.
If the attacker tries to access the same file with the COPY command it will result with an error:
Invoking Lambda Functions with CREATE EXTERNAL FUNCTION
Redshift's default role also has permission to invoke any lambda function containing the string “redshift”:
The following flow diagram shows the possible attack paths:
If an attacker tries to invoke the lambda function “lateral_movement_with_redshift_lambda” with the low-privilege AWS principal, it will result with permission denied:
If the attacker tries to do the same from within Redshift:
The lambda will be invoked successfully:
Extracting Temporary Credentials from EC2:
A smart attacker will follow the golden path and will try to extend the grip. Using the COPY command, an attacker can execute commands over SSH on EC2, which in turn will allow them to extract the credentials attached to that instance.
Prerequisites:
- EC2 should have an IAM role attached
- EC2 authorized_keys should contain the Redshift cluster public key
- EC2 should use the IMDS
- Manifest file should be uploaded to a location in S3
To extract EC2 credentials, an attacker can take advantage of the Instance Metadata Service (IMDS). By querying the IMDS it's possible to retrieve the temporary credentials attached to the instance along with other metadata information.
To do so, the attacker can execute the following command in the EC2:
The attacker can upload the following manifest file with the above command to S3:
Then execute it from Redshift and load the information into the “listing” table:
To view the output of the command, the attacker can query the table they created:
Now the attacker needs to modify the manifest command to contain the role name returned in the previous step and re-execute one more time to get the credentials. Also, since the credentials can be long, it is necessary to encode the output in base64:
Attackers that execute the command will get the FULL credentials encoded in base64:
The attacker can decode the result back to a readable text and extract the credentials:
Summary
We saw some powerful attack vectors that an attacker can perform by leveraging ‘redshift:CreateCluster’ permission to escalate privileges, move laterally, and eventually access different resources and exfiltrate sensitive data.
Along with the powerful features that Redshift provides, it’s important to make sure that we use the principle of least privilege and keep in mind that attackers may use legit actions in their quest. For that reason, you’ll want to continuously monitor the logs for suspicious activity.